Android 内部的 Room 是如何工作的?
在创建 Room 数据库后第一次编译代码时,Room 会自动生成 @Database 和 @Dao 注释类的实现。前面示例中的 UserDatabase 和 UserDao 的实现是由 Room 注释处理器自动生成的。自动生成的代码可以在 build/generated/source/kapt/ 文件夹中找到。在我们的示例中,UserDatabase 实现称为 UserDatabase Impl,而 UserDao 实现称为 UserDao Impl。这些是进行实际处理的类。让我们分别看一下每个实现。
当你使用 Room 创建数据库实例时,会调用createOpenHelper ()。数据库生成器()。建造()。它创建并返回一个 SupportSQLiteOpenHelper 实例,这是一个用于管理数据库创建和版本管理的帮助类。
- createInvalidationTracker() 创建一个失效跟踪器,它保存由查询修改的表的列表,并在这些表被修改时通知其回调。
- clearAllTables() 是一个从指定数据库中的所有表中删除数据的函数。
- userDao() 创建(如果尚未存在)并返回一个 UserDao Impl 实例,用于与用户的表进行交互。
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
}
}
Kotlin
public final class GfgCoursesDao_Impl implements GfgCoursesDao {
private final RoomDatabase __db;
private final EntityInsertionAdapter __insertionAdapterOfGfgCourses;
private final EntityDeletionOrUpdateAdapter __deletionAdapterOfGfgCourses;
public GfgCoursesDao_Impl(RoomDatabase __db) {
this.__db = __db;
this.__insertionAdapterOfGfgCourses = new EntityInsertionAdapter(__db) {
// Implementation
};
this.__deletionAdapterOfGfgCourses = new EntityDeletionOrUpdateAdapter(__db) {
// Implementation
};
}
@Override
public void insertAll(final GfgCourses... gfgCoursess) {
// Implementation
}
@Override
public void delete(final GfgCourses gfgCourses) {
// Implementation
}
@Override
public List getAll() {
// Implementation
}
@Override
public List loadAllByIds(final int[] gfgCoursesIds) {
// Implementation
}
@Override
public GfgCourses findByName(final String first, final String last) {
// Implementation
}
}
Kotlin
val coursesDatabase = Room.databaseBuilder(
applicationContext,
UserDatabase::class.java,
"gfg_courses_db"
).build()
Kotlin
@Override
public void delete(final GfgCourses gfgCourses) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__deletionAdapterOfGfgCourses.handle(gfgCourses);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
Kotlin
@Override
public void insertAll(final GfgCourses... gfgCoursess) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__insertionAdapterOfGfgCourses.insert(gfgCoursess);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
Kotlin
@Override
public List getAll() {
final String _sql = "SELECT * FROM gfgCoursess";
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 _result = new ArrayList(_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();
}
}
上例中的 CourseDao Impl 具有三个字段:
- __db是一个 RoomDatabase 实例,用于多种用途,包括数据库事务和查询。
- _ _insertionAdapterOfCourse是一个 EntityInsertionAdapter 实例,用于将实体插入到表中。 insertAll() 方法利用了这一点。
- __deletionAdapterOfCourse是一个 EntityDeletionOrUpdateAdapter 实例,用于从表中更新/删除实体。这是由 delete() 方法使用的。
科特林
public final class GfgCoursesDao_Impl implements GfgCoursesDao {
private final RoomDatabase __db;
private final EntityInsertionAdapter __insertionAdapterOfGfgCourses;
private final EntityDeletionOrUpdateAdapter __deletionAdapterOfGfgCourses;
public GfgCoursesDao_Impl(RoomDatabase __db) {
this.__db = __db;
this.__insertionAdapterOfGfgCourses = new EntityInsertionAdapter(__db) {
// Implementation
};
this.__deletionAdapterOfGfgCourses = new EntityDeletionOrUpdateAdapter(__db) {
// Implementation
};
}
@Override
public void insertAll(final GfgCourses... gfgCoursess) {
// Implementation
}
@Override
public void delete(final GfgCourses gfgCourses) {
// Implementation
}
@Override
public List getAll() {
// Implementation
}
@Override
public List loadAllByIds(final int[] gfgCoursesIds) {
// Implementation
}
@Override
public GfgCourses findByName(final String first, final String last) {
// Implementation
}
}
建立房间数据库
我们已经弄清楚了我们的项目成功编译后会发生什么。为了执行任何与数据库相关的操作,我们还知道我们需要一个 UserDatabase 的实例,它为我们提供了一个 UserDao 的实例。 Room 提供了一个名为 Room.databaseBuilder 的构建器方法,该方法返回 RoomDatabase.Builder 的实例,以获取 UserDatabase 的实例。通过在这个实例上调用 build() 方法,我们可以获得 UserDatabase。
科特林
val coursesDatabase = Room.databaseBuilder(
applicationContext,
UserDatabase::class.java,
"gfg_courses_db"
).build()
我们可以使用此构建器以下列方式配置我们的数据库:
- 要从资产(位于应用程序'assets/' 文件夹中)或预打包的数据库文件创建和打开数据库,请使用 createFromAsset()/createFromFile()。
- 要将数据库从一个版本迁移到另一个版本,请使用 addMigrations()。即使两个版本的模式都没有变化,每当我们更改数据库的版本时,我们都必须执行迁移。
- allowMainThreadQueries () 允许从主线程进行数据库查询。 Room 默认不允许这样做。
- 如果没有找到迁移,Room 可以使用 fallbackToDestructiveMigration() 以破坏性方式重新创建数据库表。
RoomDatabase.Builder 还包括大量用于数据库配置的其他方法。
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.
在创建 UserDatabase Impl 之后,会绕过数据库配置调用数据库的 init() 方法,然后调用 UserDatabase Impl 的 createOpenHelper() 方法。现在我们来看看UserDatabase Impl和UserDao Impl中的一些重要方法是如何实现的。
CoursesDao 中的 delete()
科特林
@Override
public void delete(final GfgCourses gfgCourses) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__deletionAdapterOfGfgCourses.handle(gfgCourses);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
CoursesDao 中的 insertAll()
科特林
@Override
public void insertAll(final GfgCourses... gfgCoursess) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__insertionAdapterOfGfgCourses.insert(gfgCoursess);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
CoursesDao 中的 getAll()
科特林
@Override
public List getAll() {
final String _sql = "SELECT * FROM gfgCoursess";
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 _result = new ArrayList(_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();
}
}
结论
可以看出,它根据@Query 注解中指定的查询生成了一个 RoomSQLiteQuery 对象。然后它创建一个游标来从数据库中检索数据。这足以基本了解 Room 内部的运作方式。