How Room Works Internally in Android?
Room autogenerates implementations of your @Database and @Dao annotated classes the first time you compile your code after creating a Room Database. The implementation of UserDatabase and UserDao in the preceding example is generated automatically by the Room annotation processor. The autogenerated code can be found in the build/generated/source/kapt/ folder. In our example, the UserDatabase implementation is called UserDatabase Impl, and the UserDao implementation is called UserDao Impl. These are the classes where the actual processing takes place. Let’s take a look at each implementation separately.
When you use Room to create a database instance, createOpenHelper() is called. databaseBuilder(). build(). It creates and returns a SupportSQLiteOpenHelper instance, which is a helper class for managing database creation and version management.
- createInvalidationTracker() creates an invalidation tracker that keeps a list of tables modified by queries and notifies its callbacks when these tables are modified.
- clearAllTables() is a function that deletes data from all tables in the specified database.
- userDao() creates (if not already present) and returns a UserDao Impl instance for interacting with the user’s table.
CourseDao Impl in the preceding example has three fields:
- __db is a RoomDatabase instance that is used for a variety of purposes including database transactions and queries.
- __insertionAdapterOfCourse is an EntityInsertionAdapter instance that is used to insert entities into a table. The insertAll() method makes use of this.
- __deletionAdapterOfCourse is an EntityDeletionOrUpdateAdapter instance that is used to update/delete entities from a table. This is employed by the delete() method.
Establishing the RoomDatabase
We’ve figured out what happens after our project is successfully compiled. In order to perform any database-related operations, we also know that we require an instance of UserDatabase, which provides us with an instance of UserDao. Room provides a builder method named Room.databaseBuilder that returns an instance of RoomDatabase.Builder in order to obtain an instance of UserDatabase. By invoking the build() method on this instance, we can obtain UserDatabase.
We can use this builder to configure our database in the following manner:
- To create and open a database from an asset (located in the application’assets/’ folder) or a pre-packaged database file, use createFromAsset()/createFromFile().
- To add database migrations from one version to another, use addMigrations(). Even if there is no change in the schema of both versions, we must perform a migration whenever we change the version of our database.
- allowMainThreadQueries() allows database queries to be made from the main thread. Room does not permit this by default.
- If no migration is found, Room can use fallbackToDestructiveMigration() to recreate database tables in a destructive manner.
RoomDatabase.Builder also includes a plethora of other methods for database configuration.
GeekTip: When we call the build() method on this RoomDatabase.Builder instance, Room validates and generates an instance of the autogenerated gfgCourses:: class.java — also known as GFGCourses Impl.
Following the creation of UserDatabase Impl, the database’s init() method is invoked bypassing the database configuration, which in turn invokes the UserDatabase Impl’s createOpenHelper() method. Now we’ll look at how some of the important methods in UserDatabase Impl and UserDao Impl are implemented.
delete() in CoursesDao
insertAll() in CoursesDao
getAll() in CoursesDao
As can be seen, it generates a RoomSQLiteQuery object based on the query specified in the @Query annotation. It then creates a cursor to retrieve data from the database. This is sufficient to gain a basic understanding of how Room operates internally.