为了防止查询阻塞 UI,Room 不允许在主线程上访问数据库。此限制意味着您必须使DAO 查询异步。Room 库包含与几个不同框架的集成,以提供异步查询执行。
DAO 查询分为三类
- 一次性写入查询,用于在数据库中插入、更新或删除数据。
- 一次性读取查询,仅从您的数据库中读取一次数据,并返回该时间点数据库快照的结果。
- 可观察读取查询,每当底层数据库表发生更改时,都会从您的数据库中读取数据,并发出新值以反映这些更改。
语言和框架选项
Room 提供与特定语言功能和库的互操作性的集成支持。下表显示了基于查询类型和框架的适用返回类型
查询类型 | Kotlin 语言特性 | RxJava | Guava | Jetpack Lifecycle |
---|---|---|---|---|
一次性写入 | 协程 (suspend ) |
Single<T> , Maybe<T> , Completable |
ListenableFuture<T> |
N/A |
一次性读取 | 协程 (suspend ) |
Single<T> , Maybe<T> |
ListenableFuture<T> |
N/A |
可观察读取 | Flow<T> |
Flowable<T> , Publisher<T> , Observable<T> |
N/A | LiveData<T> |
本指南演示了三种可以在 DAO 中使用这些集成来实现异步查询的方法。
使用 Flow 和协程的 Kotlin
Kotlin 提供了允许您在没有第三方框架的情况下编写异步查询的语言特性
- 在 Room 2.2 及更高版本中,您可以使用 Kotlin 的Flow 功能来编写可观察查询。
- 在 Room 2.1 及更高版本中,您可以使用
suspend
关键字,结合 Kotlin 协程 使您的 DAO 查询异步化。
Java 与 RxJava
如果您的应用使用 Java 编程语言,您可以使用 RxJava 框架中的特殊返回类型来编写异步 DAO 方法。Room 支持以下 RxJava 2 返回类型
- 对于一次性查询,Room 2.1 及更高版本支持
Completable
、Single<T>
和Maybe<T>
返回类型。 - 对于可观察查询,Room 支持
Publisher<T>
、Flowable<T>
和Observable<T>
返回类型。
此外,Room 2.3 及更高版本支持 RxJava 3。
Java 与 LiveData 和 Guava
如果您的应用使用 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 查询的更多信息,请参阅以下其他资源