Implementing Room Databases with Kotlin Coroutines in Android

Anil Kr Mourya
5 min readJul 7, 2023

--

Coroutines

Coroutines are a feature in Kotlin that allow for asynchronous programming. They provide a way to write highly readable and sequential code while executing long-running tasks, such as network requests or database operations, asynchronously. Coroutines simplify asynchronous programming by providing structured concurrency, allowing developers to write asynchronous code in a more linear and sequential style, similar to synchronous code.

Coroutines are lightweight and can be seen as light threads, but they are not bound to any particular thread. They can suspend and resume their execution at certain points without blocking the underlying thread. This allows for efficient utilization of system resources and enables concurrent and parallel execution of tasks.

Using coroutines, you can define suspending functions that can be paused and resumed at any point, making it easy to perform long-running operations without blocking the main thread. Coroutines can be launched using the launch or async builders, and you can use various coroutine builders and operators to control the execution flow, handle exceptions, and combine multiple coroutines. Continue learning………..

Room database

Room is a powerful persistence library provided by the Android Jetpack components. It is built on top of SQLite and provides an abstraction layer that simplifies database operations in Android applications. Room is designed to make it easier for developers to work with databases by providing compile-time verification of SQL queries and reducing boilerplate code.

Room database entities

  1. Definition: An entity is a Kotlin or Java class that represents a table in your database. Each instance of the entity class corresponds to a row in the table, and the member variables represent columns in the table.
  2. Annotations: To define an entity class, you annotate it with the @Entity annotation. This annotation specifies the name of the table associated with the entity. You can also provide additional options such as indices, foreign key constraints, and table inheritance.
  3. Member variables: The member variables in the entity class represent columns in the table. You annotate each variable with @ColumnInfo to specify the column name, or you can omit the annotation to use the variable name as the column name by default. You can also use @PrimaryKey annotation to designate a variable as the primary key.
  4. Relationships: Entities can have relationships with other entities, allowing you to define complex database structures. You can establish one-to-one, one-to-many, or many-to-many relationships between entities using annotations such as @ForeignKey, @Relation, or @Embedded.
  5. Data types: Entity class member variables can have various data types, including primitive types, strings, dates, and custom types. Room supports mapping these data types to appropriate database column types automatically.
  6. DAO access: Entities are accessed through the Data Access Object (DAO) interfaces in Room. DAOs provide methods to perform database operations on entities, such as inserting, updating, deleting, and querying data. You define the necessary DAO methods and annotate them with appropriate Room annotations, such as @Insert, @Update, @Delete, or @Query.
  7. Data integrity: Entities allow you to define constraints and enforce data integrity at the database level. You can specify uniqueness constraints, foreign key constraints, and other constraints using annotations like @Unique, @ForeignKey, or @Check.

Advantages of using Room database in Android applications:

  1. Object-Relational Mapping (ORM): Room provides an ORM approach, allowing you to map your database tables to Kotlin or Java objects. This abstraction makes it easier to work with data as objects rather than dealing with raw SQL queries.
  2. Compile-time SQL query verification: Room performs compile-time verification of your SQL queries. It checks the query syntax, column names, and table names at compile-time, reducing the risk of runtime errors caused by typos or incorrect SQL statements.
  3. SQL query flexibility: Although Room handles SQL queries for you, it also provides flexibility for more complex scenarios. You can write custom SQL queries using the @Query annotation, giving you control over specific database operations when needed.
  4. Efficient database operations: Room is optimized for performance and provides efficient data access and manipulation. It uses SQLite as its underlying database engine, which is a proven and reliable database solution for Android.
  5. LiveData and RxJava integration: Room seamlessly integrates with LiveData and RxJava, allowing you to observe database changes and receive updates automatically when data changes. This enables real-time updates in your user interface and simplifies data synchronization.
  6. Data migration support: Room simplifies the process of handling database schema changes and data migrations. It provides built-in support for database versioning and allows you to define migration strategies to handle changes in your database schema over time.
  7. Testing support: Room provides testing utilities that make it easier to write unit tests and perform database operations during testing. It allows you to run tests on an in-memory database or with a test-specific database, ensuring reliable and consistent testing of your data access layer.

To implement Room database in Android Studio, follow these steps:

1- Add project dependencies: Open your project’s build.gradle file and add the following dependencies in the dependencies block:

plugins { 
id 'kotlin-kapt'
}
  implementation 'androidx.room:room-runtime:2.5.2'
annotationProcessor 'androidx.room:room-compiler:2.5.2'

kapt("androidx.room:room-compiler:2.5.2")

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.2'

implementation 'androidx.room:room-ktx:2.5.2'

2- Entity class: An Entity represents a table in your database. Create a new class and annotate it with @Entity. Define your table columns as member variables and annotate them with @PrimaryKey (for primary key) and @ColumnInfo (for column name).


@Entity
data class TaskItem(
@ColumnInfo(name = "title")
var taskname: String,
@ColumnInfo(name = "Description")
var TaskDescription: String,
@ColumnInfo(name = "priority")
var priority: Int

){
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Int=0
}

3- DAO (Data Access Object) interface: DAO provides methods to interact with your database. Create a new interface and annotate it with @Dao. Define methods for inserting, updating, deleting, and querying data using annotations like @Insert, @Update, @Delete, and @Query.

@Dao
interface TaskDao {

@Insert
suspend fun inserttaskItem(taskItem: TaskItem)

@Query("SELECT * FROM taskItem ORDER BY id DESC")
suspend fun getAllTask(): List<TaskItem>
@Delete
suspend fun deletitem(id: TaskItem)
@Update
suspend fun updatetak(taskItem: TaskItem)
}

4- Initialize Room Database class: Create a class that extends RoomDatabase. Annotate it with @Database and define the entities and version number. Provide an abstract method to retrieve the DAO. and Create an instance of your Room database by using the Room.databaseBuilder() method. You can initialize it in your Application class or an activity.

@Database(entities = [TaskItem::class], version = 1)
abstract class TaskDatabase : RoomDatabase() {
abstract fun TaskDao():TaskDao
companion object{
@Volatile private var inastance: TaskDatabase? =null
private val LOCK = Any()

operator fun invoke(context: Context): TaskDatabase {
return inastance ?: synchronized(LOCK){
inastance ?: Builddatabase(context).also {
inastance=it
}
}
}
private fun Builddatabase(context: Context)= Room.databaseBuilder(context.applicationContext,TaskDatabase::class.java,"Taskbardb").build()
}
}

5- Add data in database using Coroutines:-

 GlobalScope.launch {
context?.let {

val taskItem = TaskItem(binding.etName.text.toString(),binding.etDescreptiuon.text.toString(),0);

TaskDatabase(it).TaskDao().inserttaskItem(taskItem)


}


}

6- Get data from database using Coroutines:-

       GlobalScope.launch {


withContext(Dispatchers.Main) {
context?.let {
if (TaskDatabase(it).TaskDao().getAllTask().isNotEmpty()) {

TaskDatabase(it).TaskDao().getAllTask()

}
}

}



Log.e("TAG", "onViewCreated: " + TaskDatabase(requireContext()).TaskDao().getAllTask())
}

7- Delete data from database using Coroutines:-

 GlobalScope.launch {
TaskDatabase(context!!).TaskDao().deletitem(taskItem)


}

9- Update data from database using Coroutines:-


GlobalScope.launch {
TaskDatabase(it).TaskDao().updatetak(taskItem)

}

Conclusion

By combining Room Database with Kotlin Coroutines in Android development, you can achieve efficient and asynchronous data access. Room simplifies the management of the SQLite database by providing an object-oriented approach and compile-time SQL query verification. Kotlin Coroutines, on the other hand, allow for writing asynchronous code in a sequential and structured manner, enhancing code readability and maintainability.

The integration of Room with Kotlin Coroutines enables you to write clean and concise code for database operations. You can leverage coroutines’ suspend functions and Room’s asynchronous support to perform database operations on background threads without blocking the main thread. This results in smoother user interfaces and better performance.

Project link

Thank you for Reading.

--

--