Để tránh trường hợp các truy vấn chặn giao diện người dùng, Room không cho phép truy cập cơ sở dữ liệu trên luồng chính. Hạn chế này có nghĩa là bạn phải tạo truy vấn DAO ở chế độ không đồng bộ. Thư viện Room bao gồm quá trình tích hợp với nhiều khung để thực thi truy vấn không đồng bộ.
Chúng tôi phân loại truy vấn DAO thành 3 danh mục sau:
- Truy vấn ghi một lần: chèn, cập nhật hoặc xoá dữ liệu trong cơ sở dữ liệu.
- Truy vấn đọc một lần: chỉ đọc dữ liệu từ cơ sở dữ liệu một lần và trả về kết quả kèm theo thông tin tổng quan nhanh về cơ sở dữ liệu tại thời điểm đó.
- Truy vấn đọc có thể quan sát: đọc dữ liệu từ cơ sở dữ liệu mỗi khi bảng cơ sở dữ liệu cơ bản thay đổi và tạo ra giá trị mới để phản ánh những thay đổi đó.
Tuỳ chọn khung và ngôn ngữ
Room hỗ trợ quá trình tích hợp để có khả năng tương tác với các tính năng và thư viện ngôn ngữ cụ thể. Bảng sau đây trình bày các loại dữ liệu trả về (nếu có) dựa trên loại truy vấn và khung:
Loại truy vấn | Tính năng ngôn ngữ Kotlin | RxJava | Guava | Vòng đời Jetpack |
---|---|---|---|---|
Ghi một lần | Coroutine (suspend ) |
Single<T> , Maybe<T> ,
Completable |
ListenableFuture<T> |
Không có |
Đọc một lần | Coroutine (suspend ) |
Single<T> , Maybe<T> |
ListenableFuture<T> |
Không có |
Đọc có thể quan sát | Flow<T> |
Flowable<T> , Publisher<T> ,
Observable<T> |
Không có | LiveData<T> |
Hướng dẫn này trình bày 3 cách mà bạn có thể sử dụng những quá trình tích hợp này để triển khai truy vấn không đồng bộ trong DAO của mình.
Kotlin với Flow và coroutine
Kotlin cung cấp những tính năng ngôn ngữ cho phép bạn ghi các truy vấn không đồng bộ mà không cần khung của bên thứ ba:
- Trong Room 2.2 trở lên, bạn có thể dùng chức năng Flow của Kotlin để ghi các truy vấn có thể quan sát.
- Trong Room 2.1 trở lên, bạn có thể dùng từ khoá
suspend
để tạo truy vấn DAO ở chế độ không đồng bộ bằng coroutine của Kotlin.
Java với RxJava
Nếu ứng dụng của bạn dùng ngôn ngữ lập trình Java, thì bạn có thể sử dụng các loại dữ liệu trả về chuyên biệt từ khung RxJava để ghi các phương thức DAO không đồng bộ. Room hỗ trợ các kiểu dữ liệu trả về của RxJava 2 sau đây:
- Đối với truy vấn một lần, Room 2.1 trở lên hỗ trợ các kiểu dữ liệu trả về
Completable
,Single<T>
vàMaybe<T>
. - Đối với truy vấn có thể quan sát, Room hỗ trợ các kiểu dữ liệu trả về
Publisher<T>
,Flowable<T>
vàObservable<T>
.
Ngoài ra, Room 2.3 trở lên cũng hỗ trợ RxJava 3.
Java với LiveData và Guava
Nếu ứng dụng của bạn dùng ngôn ngữ lập trình Java và bạn không muốn dùng khung RxJava, thì bạn có thể sử dụng những phương án thay thế sau để ghi các truy vấn không đồng bộ:
- Bạn có thể dùng lớp trình bao bọc
LiveData
của Jetpack để ghi các truy vấn có thể quan sát không đồng bộ. - Bạn có thể dùng trình bao bọc
ListenableFuture<T>
của Guava để ghi các truy vấn một lần không đồng bộ.
Ghi các truy vấn một lần không đồng bộ
Truy vấn một lần là các thao tác đối với cơ sở dữ liệu chỉ chạy một lần và lấy thông tin tổng quan nhanh về dữ liệu tại thời điểm thực thi. Dưới đây là một số ví dụ về truy vấn một lần không đồng bộ:
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); }
Ghi các truy vấn có thể quan sát
Truy vấn có thể quan sát là các thao tác đọc tạo ra giá trị mới mỗi khi có thay đổi đối với các bảng mà truy vấn tham chiếu đến. Một lợi ích của loại truy vấn này là giúp bạn luôn cập nhật danh sách các mục hiển thị khi các mục trong cơ sở dữ liệu cơ bản được chèn, cập nhật hoặc xoá. Dưới đây là một số ví dụ về truy vấn có thể quan sát:
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); }
Tài nguyên khác
Để tìm hiểu thêm về các truy vấn DAO không đồng bộ, hãy xem những tài nguyên bổ sung sau đây: