@DaointerfaceUserDao{@Insert(onConflict=OnConflictStrategy.REPLACE)suspendfuninsertUsers(varargusers:User)@UpdatesuspendfunupdateUsers(varargusers:User)@DeletesuspendfundeleteUsers(varargusers:User)@Query("SELECT * FROM user WHERE id = :id")suspendfunloadUserById(id:Int):User@Query("SELECT * from user WHERE region IN (:regions)")suspendfunloadUsersByRegion(regions:List<String>):List<User>}
Java
@DaopublicinterfaceUserDao{@Insert(onConflict=OnConflictStrategy.REPLACE)publicCompletableinsertUsers(List<User>users);@UpdatepublicCompletableupdateUsers(List<User>users);@DeletepublicCompletabledeleteUsers(List<User>users);@Query("SELECT * FROM user WHERE id = :id")publicSingle<User>loadUserById(intid);@Query("SELECT * from user WHERE region IN (:regions)")publicSingle<List<User>>loadUsersByRegion(List<String>regions);}
Java
@DaopublicinterfaceUserDao{// Returns the number of users inserted.@Insert(onConflict=OnConflictStrategy.REPLACE)publicListenableFuture<Integer>insertUsers(List<User>users);// Returns the number of users updated.@UpdatepublicListenableFuture<Integer>updateUsers(List<User>users);// Returns the number of users deleted.@DeletepublicListenableFuture<Integer>deleteUsers(List<User>users);@Query("SELECT * FROM user WHERE id = :id")publicListenableFuture<User>loadUserById(intid);@Query("SELECT * from user WHERE region IN (:regions)")publicListenableFuture<List<User>>loadUsersByRegion(List<String>regions);}
@DaointerfaceUserDao{@Query("SELECT * FROM user WHERE id = :id")funloadUserById(id:Int):Flow<User>@Query("SELECT * from user WHERE region IN (:regions)")funloadUsersByRegion(regions:List<String>):Flow<List<User>>
}
Java
@DaopublicinterfaceUserDao{@Query("SELECT * FROM user WHERE id = :id")publicFlowable<User>loadUserById(intid);@Query("SELECT * from user WHERE region IN (:regions)")publicFlowable<List<User>>loadUsersByRegion(List<String>regions);}
Java
@DaopublicinterfaceUserDao{@Query("SELECT * FROM user WHERE id = :id")publicLiveData<User>loadUserById(intid);@Query("SELECT * from user WHERE region IN (:regions)")publicLiveData<List<User>>loadUsersByRegion(List<String>regions);}
[null,null,["最后更新时间 (UTC):2025-07-27。"],[],[],null,["# Write asynchronous DAO queries\n\nTo prevent queries from blocking the UI, Room does not allow database access on\nthe main thread. This restriction means that you must make your [DAO\nqueries](/training/data-storage/room/accessing-data) asynchronous. The Room\nlibrary includes integrations with several different frameworks to provide\nasynchronous query execution.\n\nDAO queries fall into three categories:\n\n- *One-shot write* queries that insert, update, or delete data in the database.\n- *One-shot read* queries that read data from your database only once and return a result with the snapshot of the database at that time.\n- *Observable read* queries that read data from your database every time the underlying database tables change and emit new values to reflect those changes.\n\nLanguage and framework options\n------------------------------\n\nRoom provides integration support for interoperability with specific language\nfeatures and libraries. The following table shows applicable return types based\non query type and framework:\n\n| Query type | Kotlin language features | RxJava | Guava | Jetpack Lifecycle |\n|-----------------|--------------------------|------------------------------------------------|-----------------------|-------------------|\n| One-shot write | Coroutines (`suspend`) | `Single\u003cT\u003e`, `Maybe\u003cT\u003e`, `Completable` | `ListenableFuture\u003cT\u003e` | N/A |\n| One-shot read | Coroutines (`suspend`) | `Single\u003cT\u003e`, `Maybe\u003cT\u003e` | `ListenableFuture\u003cT\u003e` | N/A |\n| Observable read | `Flow\u003cT\u003e` | `Flowable\u003cT\u003e`, `Publisher\u003cT\u003e`, `Observable\u003cT\u003e` | N/A | `LiveData\u003cT\u003e` |\n\nThis guide demonstrates three possible ways that you can use these integrations\nto implement asynchronous queries in your DAOs.\n\n### Kotlin with Flow and couroutines\n\nKotlin provides language features that allow you to write asynchronous queries\nwithout third-party frameworks:\n\n- In Room 2.2 and higher, you can use Kotlin's [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/) functionality to write observable queries.\n- In Room 2.1 and higher, you can use the `suspend` keyword to make your DAO queries asynchronous using [Kotlin coroutines](/kotlin/coroutines).\n\n| **Note:** To use Kotlin Flow and coroutines with Room, you must include the `room-ktx` artifact in your `build.gradle` file. For more information, see [Declaring\n| dependencies](/jetpack/androidx/releases/room#declaring_dependencies).\n\n### Java with RxJava\n\nIf your app uses the Java programming language, you can use specialized return\ntypes from the RxJava framework to write asynchronous DAO methods. Room provides\nsupport for the following RxJava 2 return types:\n\n- For one-shot queries, Room 2.1 and higher supports the [`Completable`](http://reactivex.io/RxJava/javadoc/io/reactivex/Completable), [`Single\u003cT\u003e`](http://reactivex.io/RxJava/javadoc/io/reactivex/Single), and [`Maybe\u003cT\u003e`](http://reactivex.io/RxJava/javadoc/io/reactivex/Maybe) return types.\n- For observable queries, Room supports the [`Publisher\u003cT\u003e`](http://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/org/reactivestreams/Publisher), [`Flowable\u003cT\u003e`](http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Flowable), and [`Observable\u003cT\u003e`](http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Observable) return types.\n\nAdditionally, Room 2.3 and higher supports RxJava 3.\n| **Note:** To use RxJava with Room, you must include either the `room-rxjava2` artifact or the `room-rxjava3` artifact in your `build.gradle` file. For more information, see [Declaring\n| dependencies](/jetpack/androidx/releases/room#declaring_dependencies).\n\n### Java with LiveData and Guava\n\nIf your app uses the Java programming language and you do not want to use the\nRxJava framework, you can use the following alternatives to write asynchronous\nqueries:\n\n- You can use the [`LiveData`](/reference/androidx/lifecycle/LiveData) wrapper class from Jetpack to write asynchronous observable queries.\n- You can use the [`ListenableFuture\u003cT\u003e`](https://guava.dev/releases/21.0/api/docs/com/google/common/util/concurrent/ListenableFuture) wrapper from Guava to write asynchronous one-shot queries.\n\n| **Note:** To use Guava with Room, you must include the `room-guava` artifact in your `build.gradle` file. For more information, see [Declaring\n| dependencies](/jetpack/androidx/releases/room#declaring_dependencies).\n\nWrite asynchronous one-shot queries\n-----------------------------------\n\nOne-shot queries are database operations that only run once and grab a snapshot\nof data at the time of execution. Here are some examples of asynchronous\none-shot queries: \n\n### Kotlin\n\n```kotlin\n@Dao\ninterface UserDao {\n @Insert(onConflict = OnConflictStrategy.REPLACE)\n suspend fun insertUsers(vararg users: User)\n\n @Update\n suspend fun updateUsers(vararg users: User)\n\n @Delete\n suspend fun deleteUsers(vararg users: User)\n\n @Query(\"SELECT * FROM user WHERE id = :id\")\n suspend fun loadUserById(id: Int): User\n\n @Query(\"SELECT * from user WHERE region IN (:regions)\")\n suspend fun loadUsersByRegion(regions: List\u003cString\u003e): List\u003cUser\u003e\n}\n```\n\n### Java\n\n```java\n@Dao\npublic interface UserDao {\n @Insert(onConflict = OnConflictStrategy.REPLACE)\n public Completable insertUsers(List\u003cUser\u003e users);\n\n @Update\n public Completable updateUsers(List\u003cUser\u003e users);\n\n @Delete\n public Completable deleteUsers(List\u003cUser\u003e users);\n\n @Query(\"SELECT * FROM user WHERE id = :id\")\n public Single\u003cUser\u003e loadUserById(int id);\n\n @Query(\"SELECT * from user WHERE region IN (:regions)\")\n public Single\u003cList\u003cUser\u003e\u003e loadUsersByRegion(List\u003cString\u003e regions);\n}\n```\n\n### Java\n\n```java\n@Dao\npublic interface UserDao {\n // Returns the number of users inserted.\n @Insert(onConflict = OnConflictStrategy.REPLACE)\n public ListenableFuture\u003cInteger\u003e insertUsers(List\u003cUser\u003e users);\n\n // Returns the number of users updated.\n @Update\n public ListenableFuture\u003cInteger\u003e updateUsers(List\u003cUser\u003e users);\n\n // Returns the number of users deleted.\n @Delete\n public ListenableFuture\u003cInteger\u003e deleteUsers(List\u003cUser\u003e users);\n\n @Query(\"SELECT * FROM user WHERE id = :id\")\n public ListenableFuture\u003cUser\u003e loadUserById(int id);\n\n @Query(\"SELECT * from user WHERE region IN (:regions)\")\n public ListenableFuture\u003cList\u003cUser\u003e\u003e loadUsersByRegion(List\u003cString\u003e regions);\n}\n```\n\nWrite observable queries\n------------------------\n\nObservable queries are read operations that emit new values whenever there are\nchanges to any of the tables that are referenced by the query. One way you might\nuse this is to help you keep a displayed list of items up to date as the items\nin the underlying database are inserted, updated, or removed. Here are some\nexamples of observable queries: \n\n### Kotlin\n\n```kotlin\n@Dao\ninterface UserDao {\n @Query(\"SELECT * FROM user WHERE id = :id\")\n fun loadUserById(id: Int): Flow\u003cUser\u003e\n\n @Query(\"SELECT * from user WHERE region IN (:regions)\")\n fun loadUsersByRegion(regions: List\u003cString\u003e): Flow\u003cList\u003cUser\u003e\u003e\n}\n```\n\n### Java\n\n```java\n@Dao\npublic interface UserDao {\n @Query(\"SELECT * FROM user WHERE id = :id\")\n public Flowable\u003cUser\u003e loadUserById(int id);\n\n @Query(\"SELECT * from user WHERE region IN (:regions)\")\n public Flowable\u003cList\u003cUser\u003e\u003e loadUsersByRegion(List\u003cString\u003e regions);\n}\n```\n\n### Java\n\n```java\n@Dao\npublic interface UserDao {\n @Query(\"SELECT * FROM user WHERE id = :id\")\n public LiveData\u003cUser\u003e loadUserById(int id);\n\n @Query(\"SELECT * from user WHERE region IN (:regions)\")\n public LiveData\u003cList\u003cUser\u003e\u003e loadUsersByRegion(List\u003cString\u003e regions);\n}\n```\n| **Note:** Observable queries in Room have one important limitation: the query reruns whenever any row in the table is updated, whether or not that row is in the result set. You can ensure that the UI is only notified when the actual query results change by applying the `distinctUntilChanged()` operator from the corresponding library: [Flow](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/distinct-until-changed), [RxJava](http://reactivex.io/documentation/operators/distinct), or [LiveData](/reference/androidx/lifecycle/Transformations#distinctUntilChanged(androidx.lifecycle.LiveData%3CX%3E)).\n\nAdditional resources\n--------------------\n\nTo learn more about asynchronous DAO queries, see the following additional\nresources:\n\n### Blogs\n\n- [Room \\& Flow](https://medium.com/androiddevelopers/room-flow-273acffe5b57)"]]