Open In App

How Room Works Internally in Android?

Improve
Improve
Like Article
Like
Save
Share
Report

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.

  1. createInvalidationTracker() creates an invalidation tracker that keeps a list of tables modified by queries and notifies its callbacks when these tables are modified.
  2. clearAllTables() is a function that deletes data from all tables in the specified database.
  3. userDao() creates (if not already present) and returns a UserDao Impl instance for interacting with the user’s table.

Kotlin




public final class GfgCoursesDatabase_Impl extends GfgCoursesDatabase {
   
  private volatile GfgCoursesDao _gfgCoursesDao;
 
  @Override
  protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {
    // Implementation
  }
 
  @Override
  protected InvalidationTracker createInvalidationTracker() {
    // Implementation
  }
 
  @Override
  public void clearAllTables() {
    // Implementation
  }
 
  @Override
  public GfgCoursesDao gfgCoursesDao() {
    // Implementation
  }
}


CourseDao Impl in the preceding example has three fields:

  1. __db is a RoomDatabase instance that is used for a variety of purposes including database transactions and queries.
  2. __insertionAdapterOfCourse is an EntityInsertionAdapter instance that is used to insert entities into a table. The insertAll() method makes use of this.
  3. __deletionAdapterOfCourse is an EntityDeletionOrUpdateAdapter instance that is used to update/delete entities from a table. This is employed by the delete() method.

Kotlin




public final class GfgCoursesDao_Impl implements GfgCoursesDao {
  private final RoomDatabase __db;
 
  private final EntityInsertionAdapter<GfgCourses> __insertionAdapterOfGfgCourses;
 
  private final EntityDeletionOrUpdateAdapter<GfgCourses> __deletionAdapterOfGfgCourses;
 
  public GfgCoursesDao_Impl(RoomDatabase __db) {
    this.__db = __db;
    this.__insertionAdapterOfGfgCourses = new EntityInsertionAdapter<GfgCourses>(__db) {
      // Implementation
    };
    this.__deletionAdapterOfGfgCourses = new EntityDeletionOrUpdateAdapter<GfgCourses>(__db) {
      // Implementation
    };
  }
 
  @Override
  public void insertAll(final GfgCourses... gfgCoursess) {
    // Implementation
  }
 
  @Override
  public void delete(final GfgCourses gfgCourses) {
    // Implementation
  }
 
  @Override
  public List<GfgCourses> getAll() {
    // Implementation
  }
 
  @Override
  public List<GfgCourses> loadAllByIds(final int[] gfgCoursesIds) {
    // Implementation
  }
 
  @Override
  public GfgCourses findByName(final String first, final String last) {
    // Implementation
  }
}


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.

Kotlin




val coursesDatabase = Room.databaseBuilder(
    applicationContext,
    UserDatabase::class.java,
    "gfg_courses_db"
).build()


We can use this builder to configure our database in the following manner:

  1. To create and open a database from an asset (located in the application’assets/’ folder) or a pre-packaged database file, use createFromAsset()/createFromFile().
  2. 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.
  3. allowMainThreadQueries() allows database queries to be made from the main thread. Room does not permit this by default.
  4. 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

Kotlin




@Override
public void delete(final GfgCourses gfgCourses) {
  __db.assertNotSuspendingTransaction();
  __db.beginTransaction();
  try {
    __deletionAdapterOfGfgCourses.handle(gfgCourses);
    __db.setTransactionSuccessful();
  } finally {
    __db.endTransaction();
  }
}


insertAll() in CoursesDao

Kotlin




@Override
public void insertAll(final GfgCourses... gfgCoursess) {
  __db.assertNotSuspendingTransaction();
  __db.beginTransaction();
  try {
    __insertionAdapterOfGfgCourses.insert(gfgCoursess);
    __db.setTransactionSuccessful();
  } finally {
    __db.endTransaction();
  }
}


getAll() in CoursesDao

Kotlin




@Override
public List<GfgCourses> getAll() {
  final String _sql = "SELECT * FROM gfgCourses";
  final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
  __db.assertNotSuspendingTransaction();
  final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
  try {
    final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "courseID");
    final int _cursorIndexOfCourseNameName = CursorUtil.getColumnIndexOrThrow(_cursor, "course_name");
    final int _cursorIndexOfCoursePriceName = CursorUtil.getColumnIndexOrThrow(_cursor, "course_price");
    final List<GfgCourses> _result = new ArrayList<GfgCourses>(_cursor.getCount());
    while(_cursor.moveToNext()) {
      final GfgCourses _item;
      final int _tmpUid;
      _tmpUid = _cursor.getInt(_cursorIndexOfUid);
      final String _tmpCourseNameName;
      _tmpCourseNameName = _cursor.getString(_cursorIndexOfCourseNameName);
      final String _tmpCoursePriceName;
      _tmpCoursePriceName = _cursor.getString(_cursorIndexOfCoursePriceName);
      _item = new GfgCourses(_tmpUid,_tmpCourseNameName,_tmpCoursePriceName);
      _result.add(_item);
    }
    return _result;
  } finally {
    _cursor.close();
    _statement.release();
  }
}


Conclusion

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.



Last Updated : 14 Sep, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads