注意:本文是高级 Room 系列的一部分,该系列涵盖了有关 Room 持久性库的所有详细信息。
那么,让我们开始吧。
在之前的文章中,我们讨论了如何使用 Room 库(Google Jetpack项目的一部分)在 Android 应用程序中创建关系持久性。Room 使开发人员可以非常轻松地设置数据库并开始在生产中使用它。
在本文中,我们将重点介绍 Room 如何完成所有这些事情。
我们将使用这个项目作为参考来解释 Room 是如何做所有事情的。以下是我们项目的亮点:
- 它有一个数据库(UserDatabase),其中仅包含一个表/实体(User)。
@Database(entities = [User::class], version = 1)
abstract class UserDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
- 用户表有 3 列:uid,名字和姓氏
@Entity(tableName = USERS_TABLE)
data class User(
@PrimaryKey val uid: Int,
@ColumnInfo(name = FIRST_NAME_COLUMN) val firstName: String?,
@ColumnInfo(name = LAST_NAME_COLUMN) val lastName: String?
)
- UserDao是我们的应用程序与数据库交互的接口。
@Dao
interface UserDao {
@Query("SELECT * FROM $USERS_TABLE")
fun getAll(): List<User>
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(user: User)
}
** Room 内部工作**
创建 Room 数据库后,第一次编译代码时,Room 会自动生成您的类@Database
和带@Dao
注释的类的实现。在上面的例子中,UserDatabase
and的实现UserDao
是由 Room 注释处理器自动生成的。
注意: 您可以在 build/generated/source/kapt/ 文件夹中找到自动生成的代码。
在我们的示例中, 的实现UserDatabase
被命名为UserDatabase_Impl
, 的实现UserDao
被命名为UserDao_Impl
。这些是实际处理发生的类。让我们分别讨论这两种实现。
UserDatabase_Impl
UserDatabase_Impl的概述如下所示:
public final class UserDatabase_Impl extends UserDatabase {
private volatile UserDao _userDao;
@Override
protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {
//Implementation
}
@Override
protected InvalidationTracker createInvalidationTracker() {
//Implementation
}
@Override
public void clearAllTables() {
//Implementation
}
@Override
public UserDao userDao() {
//Implementation
}
}
-
createOpenHelper()
当您使用构建数据库实例时调用Room.databaseBuilder().build()
. 它创建并返回一个实例,SupportSQLiteOpenHelper
该实例是用于管理数据库创建和版本管理的辅助类。 -
createInvalidationTracker()
创建一个失效跟踪器,它保存由查询修改的表的列表,并通知其有关这些表的回调。 -
clearAllTables()
实现从指定数据库的所有表中删除数据的行为。 -
userDao()
创建(如果不存在)并返回用于与表UserDao_Impl
交互的实例。users
UserDao_Impl
UserDao_Impl 实现了 UserDao 中的所有方法。UserDao_Impl 的概述如下所示:
public final class UserDao_Impl implements UserDao {
private final RoomDatabase __db;
private final EntityInsertionAdapter<User> __insertionAdapterOfUser;
private final EntityDeletionOrUpdateAdapter<User> __deletionAdapterOfUser;
public UserDao_Impl(RoomDatabase __db) {
this.__db = __db;
this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) {
//Implementation
};
this.__deletionAdapterOfUser = new EntityDeletionOrUpdateAdapter<User>(__db) {
//Implementation
};
}
@Override
public void insertAll(final User... users) {
//Implementation
}
@Override
public void delete(final User user) {
//Implementation
}
@Override
public List<User> getAll() {
//Implementation
}
@Override
public List<User> loadAllByIds(final int[] userIds) {
//Implementation
}
@Override
public User findByName(final String first, final String last) {
//Implementation
}
}
在上面的例子中,UserDao_Impl
有 3 个字段: __db、__insertionAdapterOfUser和__deletionAdapterOfUser 。
- __db是 RoomDatabase 的一个实例,用于事务和查询数据库等多种用途。
-
__insertionAdapterOfUser是 EntityInsertionAdapter 的一个实例,用于将实体插入到表中。这在
insertAll()
方法中使用。 -
__deletionAdapterOfUser是 EntityDeletionOrUpdateAdapter 的一个实例,用于从表中更新/删除实体。这是在
delete()
方法中使用的。
构建 Room 数据库
到目前为止,我们已经了解了我们的项目成功编译后会发生什么。此外,我们知道我们需要一个实例,UserDatabase
它为我们提供了一个实例,UserDao
以便执行任何与数据库相关的操作。
为了获得UserDatabase,
Room 的实例,我们提供了一个名为的构建器方法Room.databaseBuilder
,它为我们提供了RoomDatabase.Builder
. 我们可以UserDatabase
通过调用build()
方法来使用这个实例。
val userDatabase = Room.databaseBuilder(
applicationContext,
UserDatabase::class.java,
"users-db"
).build()
我们可以使用这个构建器来配置我们的数据库,比如
-
createFromAsset()/createFromFile()
从资产(位于应用程序“资产/”文件夹中)/预打包的数据库文件创建和打开数据库。 -
addMigrations()
添加从一个版本到另一个版本的数据库迁移。每当我们更改数据库的版本时,即使两个版本的架构都没有更改,也需要进行迁移。 -
allowMainThreadQueries()
允许从主线程进行数据库查询。默认情况下,Room 不允许这样做。 -
fallbackToDestructiveMigration()
如果未找到迁移,则允许 Room 破坏性地重新创建数据库表。
还提供了许多其他RoomDatabase.Builder
用于数据库配置的方法。
build()
一旦我们在这个RoomDatabase.Builder
实例上调用方法,Room 就会验证并创建一个自动生成的实现的实例——即. 创建后,通过传递数据库配置调用数据库的方法,然后调用方法。现在我们将讨论前面讨论的UserDatabase_Impl和UserDao_Impl中一些重要方法的实现。UserDatabase::**class**.javaUserDatabase_ImplUserDatabase_Implinit()createOpenHelper()UserDatabase_Impl
userDao() 在 UserDatabase_Impl
@Override
public UserDao userDao() {
if (_userDao != null) {
return _userDao;
} else {
synchronized(this) {
if(_userDao == null) {
_userDao = new UserDao_Impl(this);
}
return _userDao;
}
}
}
它懒惰地创建UserDao
- ie 的实现,并在被调用UserDao_Impl
时返回它。userDao()
如我们所见,它传递了RoomDatabase
inUserDao_Impl’s
构造函数的实例。
插入所有() UserDao_Impl
@Override
public void insertAll(final User... users) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__insertionAdapterOfUser.insert(users);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
它使用__db创建事务,使用__insertionAdapterOfUser进行插入。
删除()在 UserDao_Impl
@Override
public void delete(final User user) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__deletionAdapterOfUser.handle(user);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
它使用__db创建事务,使用__deletionAdapterOfUser进行删除。
getAll() 在 UserDao_Impl
@Override
public List<User> getAll() {
final String _sql = "SELECT * FROM users";
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, "uid");
final int _cursorIndexOfFirstName = CursorUtil.getColumnIndexOrThrow(_cursor, "first_name");
final int _cursorIndexOfLastName = CursorUtil.getColumnIndexOrThrow(_cursor, "last_name");
final List<User> _result = new ArrayList<User>(_cursor.getCount());
while(_cursor.moveToNext()) {
final User _item;
final int _tmpUid;
_tmpUid = _cursor.getInt(_cursorIndexOfUid);
final String _tmpFirstName;
_tmpFirstName = _cursor.getString(_cursorIndexOfFirstName);
final String _tmpLastName;
_tmpLastName = _cursor.getString(_cursorIndexOfLastName);
_item = new User(_tmpUid,_tmpFirstName,_tmpLastName);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
_statement.release();
}
}
正如我们所见,它从注解中RoomSQLiteQuery
指定的查询创建一个对象。@Query
然后它简单地创建一个游标来从数据库中获取数据。
这足以对 Room 内部如何工作有一个基本的了解。
作者:Deepanshu
链接:How does Room work internally?
网友评论