為防止查詢封鎖 UI,Room 不允許在主執行緒上存取資料庫。此限制意味著您必須將 DAO 查詢設定為非同步。Room 資料庫包含多種不同架構的整合,以提供非同步查詢執行作業。
DAO 查詢分為三個類別:
- 「單一寫入」查詢,可在資料庫中插入、更新或刪除資料。
- 「單一讀取」查詢,只會從資料庫讀取資料一次,並傳回當時資料庫的快照結果。
- 「可觀測讀取」查詢,可在基礎資料庫資料表變更時從資料庫讀取資料,並傳回新的值以反映這些變更。
語言和架構選項
Room 提供整合支援,以實現與特定語言功能和資料庫的互通性。下表顯示了以查詢類型和架構為基礎的適用傳回類型:
查詢類型 | Kotlin 語言功能 | RxJava | Guava | Jetpack 生命週期 |
---|---|---|---|---|
單一寫入 | 協同程式 (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 中實作非同步查詢的三種方法。
Kotlin 搭配 Flow 與協同程式
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 查詢,請參閱以下其他資源: