Room Database with Kotlin Coroutines
- Authors
- Name
- Amit Shekhar
- Published on
To use Room Database with Kotlin Coroutines, we mark the DAO functions with the suspend keyword, and then call them from a coroutine.
In this blog, we will learn how to use Room Database with Kotlin Coroutines.
I am Amit Shekhar, Founder @ Outcome School, I have taught and mentored many developers, and their efforts landed them high-paying tech jobs, helped many tech companies in solving their unique problems, and created many open-source libraries being used by top companies. I am passionate about sharing knowledge through open-source, blogs, and videos.
I teach AI and Machine Learning, and Android at Outcome School.
Join Outcome School and get a high-paying tech job:
Let's get started.
I will be using this project for the implementation part. If you have not gone through the project, you should go through it and then come back. The project follows a basic MVVM Architecture for simplicity. You can find the complete code for the implementation mentioned in this blog in the project itself.
First, we need to set up our dependencies for the Room Database like below:
implementation "androidx.room:room-runtime:2.2.5"
kapt "androidx.room:room-compiler:2.2.5"
implementation "androidx.room:room-ktx:2.2.5"
Do not forget to add the Kotlin plugin for Annotation Processing in your app-level gradle file.
apply plugin: 'kotlin-kapt'
Now, create the entity which will be our data class required for Room Database, for example, User.
@Entity
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "name") val name: String?,
@ColumnInfo(name = "email") val email: String?,
@ColumnInfo(name = "avatar") val avatar: String?
)
For this User, we need to create Dao required for Room Database, which we will name as UserDao.
@Dao
interface UserDao {
@Query("SELECT * FROM user")
suspend fun getAll(): List<User>
@Insert
suspend fun insertAll(users: List<User>)
@Delete
suspend fun delete(user: User)
}
Note: We have used suspend keyword to support Coroutines so that we can call it from a Coroutine or another suspend function.
A quick note for you
No matter which tech domain you work in, get familiar with these topics:
- LLM
- RAG
- MCP
- Agent
- Fine-tuning
- Quantization
We put it all together in one video:
AI Engineering Explained: LLM, RAG, MCP, Agent, Fine-Tuning, and Quantization
No need to stop reading - bookmark it and watch later when you get time. Future you will thank you.
Now, let's get back to the topic.
Now, we need to create the AppDatabase which will extend RoomDatabase.
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
After this, we will be needing a DatabaseBuilder which will be a Singleton.
object DatabaseBuilder {
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
if (INSTANCE == null) {
synchronized(AppDatabase::class) {
if (INSTANCE == null) {
INSTANCE = buildRoomDB(context)
}
}
}
return INSTANCE!!
}
private fun buildRoomDB(context: Context) =
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"learn-kotlin-coroutines"
).build()
}
Then, we will create a DatabaseHelper interface.
interface DatabaseHelper {
suspend fun getUsers(): List<User>
suspend fun insertAll(users: List<User>)
}
Then, we will create a DatabaseHelperImpl which will implement the DatabaseHelper.
class DatabaseHelperImpl(private val appDatabase: AppDatabase) : DatabaseHelper {
override suspend fun getUsers(): List<User> = appDatabase.userDao().getAll()
override suspend fun insertAll(users: List<User>) = appDatabase.userDao().insertAll(users)
}
Note: Again, we have used the suspend so that we can call it from a coroutine or another suspend function.
Then, we can create the instance of DatabaseHelper like below:
val dbHelper = DatabaseHelperImpl(DatabaseBuilder.getInstance(applicationContext))
We can pass this instance wherever required, for example to the ViewModel and make the query to get the users from the database like below:
class RoomDBViewModel(private val apiHelper: ApiHelper, private val dbHelper: DatabaseHelper) :
ViewModel() {
init {
fetchUsers()
}
private fun fetchUsers() {
viewModelScope.launch {
try {
val usersFromDb = dbHelper.getUsers()
// here you have your usersFromDb
} catch (e: Exception) {
// handle error
}
}
}
}
This way, we are able to query the database using Kotlin Coroutines.
You can find the end-to-end implementation in this project.
To master Room, Database, suspend functions, Coroutines internals, and Offline First App Architecture hands-on, check out the Android Program by Outcome School.
Stay updated: Subscribe to our newsletter to get our latest AI and Machine Learning blogs straight to your inbox.
Frequently Asked Questions
Why do we mark Room DAO functions with suspend?
We mark the DAO functions with the suspend keyword to support Coroutines. This way, we can call them from a Coroutine or from another suspend function. The same applies to the DatabaseHelper functions that wrap the DAO calls.
Which dependencies do we need to use Room with Kotlin Coroutines?
We need room-runtime, room-compiler added through kapt, and room-ktx. We also must add the Kotlin plugin for Annotation Processing, kotlin-kapt, in the app-level gradle file.
How do we handle errors when querying Room with Coroutines?
We wrap the database call inside a try-catch block within viewModelScope.launch. If the query succeeds, we get the list of users from the database. If something goes wrong, the exception lands in the catch block, where we can handle the error.
That's it for now.
Thanks
Amit Shekhar
Founder @ Outcome School
You can connect with me on:
Follow Outcome School on:
