Room 🔗 Coroutines
Add some suspense to your database
Room 2.1 adds support for Kotlin coroutines. DAO methods can now be marked as suspending to ensure that they are not executed on the main thread. Read on to see how to use this, how it works under the hood and how to test this new functionality.
Add some suspense to your database
To use coroutines and Room in your app, update to Room 2.1 and add the new dependency to your build.gradle
file:
implementation "androidx.room:room-coroutines:${versions.room}"
You’ll also need Kotlin 1.3.0 and Coroutines 1.0.0 or newer.
You can now update your DAO methods to use suspension functions:
@Transaction
methods can also be suspending and they can call other suspending DAO functions:
You can also call suspension functions from different DAOs inside a transaction:
You can provide executors (by calling setTransactionExecutor
or setQueryExecutor
when you’re building your database) to control the threads they run on. By default this will be the same executor used for running queries on the background thread.
Testing DAO suspension functions
Testing a DAO suspending function is no different from testing any other suspending function. For example, to check that after inserting a user we are able to retrieve it, we wrap the test in a runBlocking
block:
Under the hood
To see what’s under the hood, let’s take a look at the DAO class implementation Room generates for a synchronous and for a suspending insert:
For the synchronous insert, the generated code starts a transaction, executes the insert, marks the transaction as successful and ends it. The synchronous method will just execute the insert on whatever thread it’s called from.
Now let’s see how adding the suspend modifier changes things:
The generated code ensures that the insert happens off of the UI thread. In our suspend function implementation, the same logic from the synchronous insert method is wrapped in a `Callable`. Room calls the `CoroutinesRoom.execute` suspend function, which switches to a background dispatcher, depending on whether the database is opened and we are in a transaction or not. Here’s the implementation of the function:
Case 1. The database is opened and we are in a transaction
Here we just immediately execute the callable — i.e. the actual insertion of the user in the database
Case 2. Otherwise
Room makes sure that the work done in the Callable#call method is performed on a background thread.
Room will use different Dispatchers for transactions and queries. These are derived from the executors you provide when building your Database or by default will use the Architecture Components IO executor. This is the same executor that would be used by LiveData to do background work.
If you’re interested to check out the implementation, check out the CoroutinesRoom.java and RoomDatabase.kt
Start using Room and coroutines in your app, the database work is guaranteed to be run on a non-UI Dispatcher. Mark your DAO method with the suspend
modifier and call them from other suspend functions or coroutines!