dependencies
To use Room in your app, add the following dependencies to your app's build.gradle
file:
plugins {
id 'kotlin-kapt'
}
dependencies {
def room_version = "2.4.3"
def activityVersion = '1.3.1'
implementation("androidx.room:room-runtime:$room_version")
kapt("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
implementation "androidx.activity:activity-ktx:$activityVersion"
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
}
Primary components
There are three major components in Room:
- The database class that holds the database and serves as the main access point for the underlying connection to your app's persisted data.
- Data entities that represent tables in your app's database.
- Data access objects (DAOs) that provide methods that your app can use to query, update, insert, and delete data in the database.
1: Data Entities
We define entities to represent the objects that we want to store.
By default, Room uses the class name as the database table name. If you want the table to have a different name, set the
tableName
property of the@Entity
annotation.Similarly, Room uses the field names as column names in the database by default. If you want a column to have a different name, add the@ColumnInfo
annotation to the field and set thename
property.
The following code defines a User
data entity. Each instance of User
represents a row in a user
table in the app's database.
@Entity
data class UserEntity(
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
val name: String = "",
@ColumnInfo(name = "email_id")
val email: String = ""
)
@Entity(tableName ="user-table")
Define a primary key
Each Room entity must define a primary key that uniquely identifies each row in the corresponding database table. The most straightforward way of doing this is to annotate a single column with **@PrimaryKey
@PrimaryKey val id: Int
// OR autogenerate it
@PrimaryKey(autoGenerate = true)
val id: Int = 0,
Ignore fields
@Ignore val picture: Bitmap?
2: Data access objects (DAOs)
The following code defines a DAO called UserDao
. UserDao
provides the methods that the rest of the app uses to interact with data in the user
table.
@Dao
interface UserDao {
@Insert
suspend fun insert(userEntity: UserEntity)
@Update
suspend fun update(userEntity: UserEntity)
@Delete
suspend fun delete(userEntity: UserEntity)
@Query("SELECT * FROM `user-table`")
fun fetchAllEmployees(): Flow<List<UserEntity>>
@Query("SELECT * FROM `user-table` Where id=:id")
fun fetchEmployee(id:Int): Flow<UserEntity>
}
Here we are using Flow to receive live updates from a database.
As a suspend function cannot return multiple consecutive values, we creates and returns a flow to fulfill this requirement.
Database class
The database class must satisfy the following conditions:
- The class must be annotated with a
@Database
annotation that includes anentities
array that lists all of the data entities associated with the database. - The class must be an abstract class that extends
RoomDatabase
.
For each DAO class that is associated with the database, the database class must define an abstract method that has zero arguments and returns an instance of the DAO class.
@Database(entities = [UserEntity::class], version = 1)
abstract class UserDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
// defining companion object to add functions to our DB
companion object {
@Volatile
private var INSTANCE : EmployeeDB? = null
fun getInstance(context: Context) : EmployeeDB {
var instance = INSTANCE
if (instance==null) {
instance= Room.databaseBuilder(
context.applicationContext,
UserDatabase::class.java,
"user_database"
).fallbackToDestructiveMigration().build()
INSTANCE=instance
}
return instance
}
}
Here we are first checking if our DB has already an instance. If yes than just return it.
Using in our app
override fun onCreate(savedInstanceState: Bundle?) {...
val db = UserDatabase.getInstance(this)
val userDao = db.userDao()
lifecycleScope.launch {
userDao.insert(UserEntity(name=name, email=email))
}
Fetching the data and setting recyler view.
lifecycleScope.launch {
userDao.fetchAllUsers().collect {
val list = ArrayList(it)
val itemAdapter = ItemAdapter(list)
binding.rvItemsList.adapter = itemAdapter
}
}
deleting and updating
lifecycleScope.launch {
userDao.delete(UserEntity(id))
userDao.update(UserEntity(id,name,email))
}