Android Room using Kotlin

Abhishek Srivastava
5 min readAug 12, 2020

Room is a part of the Android Architecture components which provides an abstraction layer over SQLite which allows for more robust database access while still providing the full power of SQLite.

Today we are going to discuss the basics of using the Room library and how it can enhance your workflow as a developer.

The Room library consists of 3 major components:

Entity:
The Entity represents a table within the database and has to be annotated with @Enity. Each Entity consist of a minimum of one field has to define a primary key.

DAO (Database Access Object):
In-Room you use data access objects to access and manage your data. The DAO is the main component of Room and includes methods that offer access to your app's database it has to be annotated with @Dao. DAOs are used instead of query builders and let you separate different components of your database e.g. current data and statistics, which allows you to easily test your database.

Database:
Serves as the database holder and is the main access point to your relational data. It has to be annotated with @Database and extents the RoomDatabase. It also contained and returns the Dao (Database Access Object).

Adding the needed dependencies
First, we need to add the needed dependencies that will enable us to use the Room library. We can do so with some simple lines in the build. gradle (Module: app) file

dependencies {
implementation “androidx.room:room-runtime:$room_version”
implementation “androidx.legacy:legacy-support-v4:1.0.0”
implementation ‘androidx.lifecycle:lifecycle-extensions:2.0.0’
implementation ‘androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0’
kapt “androidx.room:room-compiler:$room_version”
}

We also need to create a variable for the room version in our build.Gradle (Project) file

buildscript {
ext.room_version = '2.1.0-alpha01'
}

Entity
After importing the dependency we can start defining the Entity which represents a table in the database. In this example, we just have a simple todo list item with a title and a content field.

data class TodoEntity(
@PrimaryKey var title: String,
@ColumnInfo(name = "content") var content: String
)

Now you should start to realize that Room is based on annotations. Now let’s look at how you can autogenerate a Primarykey and change the table name.

@Entity(tableName = "todo_items")
data class TodoEntity(
@PrimaryKey(autoGenerate = true)
var id: Int,
@ColumnInfo(name = "title") var title: String,
@ColumnInfo(name = "content") var content: String
)

DAO
Next, we can start building our DAO which will contain our data queries.

@Dao
interface TodoDao {
@Query("SELECT * FROM todoentity")
fun getAll(): List<TodoEntity>
@Query("SELECT * FROM todoentity WHERE title LIKE :title")
fun findByTitle(title: String): TodoEntity
@Insert
fun insertAll(vararg todo: TodoEntity)
@Delete
fun delete(todo: TodoEntity)

@Update
fun updateTodo(vararg todos: TodoEntity)
}

Here we just define basic SQL database functionality like inserting and deleting entries. You can see that the @Query annotation is used to annotate functions that are using queries. You can also use parameters in your queries using: parameter name as you can see in the findByTitle function.

You can also make your queries observable using LiveData as you can see in this example.

@Dao
interface TodoDao {
@Query("SELECT * FROM todoentity WHERE title LIKE :title")
fun findByTitle(title: String): LiveData<List<TodoEntity>>
}

Here, you are returning a LiveData Object holding a list of TodoEntries which you can observe in your activity.

Database
After that, we can start writing the database which contains all your DAOs as abstract methods.

@Database(entities = arrayOf(TodoEntity::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun todoDao(): TodoDao
}

Here we define the version of the database and the entity and DAO that we are using.

You can also use more than one entity and define a custom build and invoke method as you can see in this example.

@Database(
entities = [TodoEntity::class, TaskEntry::class],
version = 1
)
abstract class AppDatabase : RoomDatabase(){
abstract fun TodoDao(): TodoDao
abstract fun TaskDao(): TaskDao
companion object {
@Volatile private var instance: AppDatabase? = null
private val LOCK = Any()
operator fun invoke(context: Context)= instance ?: synchronized(LOCK){
instance ?: buildDatabase(context).also { instance = it}
}
private fun buildDatabase(context: Context) = Room.databaseBuilder(context,
AppDatabase::class.java, "todo-list.db")
.build()
}
}

Accessing the Database
After defining the database we can get an instance in our activity using the Room.databaseBuilder() method.

val db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "todo-list.db"
).build()

We don’t need the Room.databaseBuilder() to get an instance of the second database example defined above. We just need to call the invoke() method and pass the activity context.

val db = AppDatabase(this)

Now we can start using the database instance to access our DAO object.

GlobalScope.launch {
db.todoDao().insertAll(TodoEntry("Title", "Content"))
data = db.todoDao().getAll()
data?.forEach {
println(it)
}
}

Database operations cannot run on the UI thread so we need to create another one. In this example, we are using Kotlin's coroutines to launch a thread for the database operations.

Testing your database
Now we can start testing our database to make sure that the read and write functionality is functioning correctly.

@RunWith(AndroidJUnit4::class)
class EnityReadWriteTest {
private lateinit var todoDao: TodoDao
private lateinit var db: AppDatabase
@Before
fun createDb() {
val context = InstrumentationRegistry.getContext()
db = Room.inMemoryDatabaseBuilder(
context, AppDatabase::class.java).build()
todoDao = db.todoDao()
}
@After
@Throws(IOException::class)
fun closeDb() {
db.close()
}
@Test
@Throws(Exception::class)
fun writeUserAndReadInList() {
val todo: TodoEntry = TodoEntry("title", "detail")
todoDao.insertAll(todo)
val todoItem = todoDao.findByTitle(todo.title)
assertThat(todoItem, equalTo(todo))
}
}

Here we insert an object into the database and read it and check if the two objects are the same.

Conclusion
Now you should know how the Room library works, how you can insert, update, get, and delete entities in the database. You have also learned how to test your database using JUnit.

You can also download project for Room from below GitHub link:-https://github.com/googlecodelabs/android-room-with-a-view

For More study About Room database, you can also refer below links:-

--

--

Abhishek Srivastava

Senior Software Engineer | Android | Java | Kotlin | Xamarin Native Android | Flutter | Go