美文网首页
Room 如何在内部工作?

Room 如何在内部工作?

作者: 小城哇哇 | 来源:发表于2022-07-17 13:40 被阅读0次

注意:本文是高级 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注释的类的实现。在上面的例子中,UserDatabaseand的实现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()如我们所见,它传递了RoomDatabaseinUserDao_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?

相关文章

网友评论

      本文标题:Room 如何在内部工作?

      本文链接:https://www.haomeiwen.com/subject/exxdirtx.html