为了防止查询阻塞 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 查询异步。
使用 RxJava 的 Java
如果您的应用使用 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。
使用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查询的更多信息,请参阅以下其他资源。