为了防止查询阻塞 UI,Room 不允许在主线程上访问数据库。此限制意味着您必须使您的 DAO 查询异步化。Room 库集成了多种不同的框架,以提供异步查询执行。
DAO 查询分为三类
- 一次性写入查询,用于在数据库中插入、更新或删除数据。
- 一次性读取查询,仅从数据库中读取数据一次,并返回当时数据库快照的结果。
- 可观察读取查询,用于在底层数据库表更改时读取数据库中的数据,并发出新值以反映这些更改。
语言和框架选项
Room 提供集成支持,以便与特定的语言特性和库进行互操作。下表显示了基于查询类型和框架的适用返回类型
查询类型 | Kotlin 语言特性 | RxJava | Guava | Jetpack Lifecycle |
---|---|---|---|---|
一次性写入 | 协程 (suspend ) |
Single<T> , Maybe<T> , Completable |
ListenableFuture<T> |
不适用 |
一次性读取 | 协程 (suspend ) |
Single<T> , Maybe<T> |
ListenableFuture<T> |
不适用 |
可观察读取 | Flow<T> |
Flowable<T> , Publisher<T> , Observable<T> |
不适用 | LiveData<T> |
本指南演示了三种可能的方式,您可以使用这些集成在 DAO 中实现异步查询。
结合 Flow 和协程使用 Kotlin
Kotlin 提供了语言特性,允许您在没有第三方框架的情况下编写异步查询
- 在 Room 2.2 及更高版本中,您可以使用 Kotlin 的 Flow 功能来编写可观察查询。
- 在 Room 2.1 及更高版本中,您可以使用
suspend
关键字通过 Kotlin 协程使您的 DAO 查询异步化。
结合 RxJava 使用 Java
如果您的应用使用 Java 编程语言,您可以使用 RxJava 框架的专用返回类型来编写异步 DAO 方法。Room 支持以下 RxJava 2 返回类型
- 对于一次性查询,Room 2.1 及更高版本支持
Completable
、Single<T>
和Maybe<T>
返回类型。 - 对于可观察查询,Room 支持
Publisher<T>
、Flowable<T>
和 注意: 要在 Room 中使用 RxJava,您必须在build.gradle
文件中包含room-rxjava2
工件或room-rxjava3
工件。有关更多信息,请参阅声明依赖项。结合 LiveData 和 Guava 使用 Java
如果您的应用使用 Java 编程语言且不想使用 RxJava 框架,您可以使用以下替代方案来编写异步查询
- 您可以使用 Jetpack 中的
LiveData
封装类来编写异步可观察查询。 - 您可以使用 Guava 中的
ListenableFuture<T>
封装类来编写异步一次性查询。
编写异步一次性查询
一次性查询是仅运行一次并获取执行时数据快照的数据库操作。以下是一些异步一次性查询的示例
Kotlin
@Dao interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertUsers(vararg users: User) @Update suspend fun updateUsers(vararg users: User) @Delete suspend fun deleteUsers(vararg users: User) @Query("SELECT * FROM user WHERE id = :id") suspend fun loadUserById(id: Int): User @Query("SELECT * from user WHERE region IN (:regions)") suspend fun loadUsersByRegion(regions: List<String>): List<User> }
Java
@Dao public interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) public Completable insertUsers(List<User> users); @Update public Completable updateUsers(List<User> users); @Delete public Completable deleteUsers(List<User> users); @Query("SELECT * FROM user WHERE id = :id") public Single<User> loadUserById(int id); @Query("SELECT * from user WHERE region IN (:regions)") public Single<List<User>> loadUsersByRegion(List<String> regions); }
Java
@Dao public interface UserDao { // Returns the number of users inserted. @Insert(onConflict = OnConflictStrategy.REPLACE) public ListenableFuture<Integer> insertUsers(List<User> users); // Returns the number of users updated. @Update public ListenableFuture<Integer> updateUsers(List<User> users); // Returns the number of users deleted. @Delete public ListenableFuture<Integer> deleteUsers(List<User> users); @Query("SELECT * FROM user WHERE id = :id") public ListenableFuture<User> loadUserById(int id); @Query("SELECT * from user WHERE region IN (:regions)") public ListenableFuture<List<User>> loadUsersByRegion(List<String> regions); }
编写可观察查询
可观察查询是读取操作,只要查询引用的任何表发生更改,就会发出新值。您可以使用此功能的一种方式是帮助您在底层数据库中的项目被插入、更新或删除时,保持显示的列表项目最新。以下是一些可观察查询的示例
Kotlin
@Dao interface UserDao { @Query("SELECT * FROM user WHERE id = :id") fun loadUserById(id: Int): Flow<User> @Query("SELECT * from user WHERE region IN (:regions)") fun loadUsersByRegion(regions: List<String>): Flow<List<User>> }
Java
@Dao public interface UserDao { @Query("SELECT * FROM user WHERE id = :id") public Flowable<User> loadUserById(int id); @Query("SELECT * from user WHERE region IN (:regions)") public Flowable<List<User>> loadUsersByRegion(List<String> regions); }
Java
@Dao public interface UserDao { @Query("SELECT * FROM user WHERE id = :id") public LiveData<User> loadUserById(int id); @Query("SELECT * from user WHERE region IN (:regions)") public LiveData<List<User>> loadUsersByRegion(List<String> regions); }
其他资源
要详细了解异步 DAO 查询,请参阅以下其他资源
博客
- 您可以使用 Jetpack 中的