Android Room is basically same as SQLiteDB but provides easier and convenient way to implement and use it.
There's three parts of Android Room.
Entity as a data transfer object and represents database table.
Dao as access point to the Entity.
RoomDatabase which holds these data and manages.
@TypeConverters(ToDoConverter::class)
@Entity(tableName = "todo")
data class EntityToDo(
@PrimaryKey(autoGenerate = true) val id : Long,
val title: String,
val content: String,
@ColumnInfo(name = "reg_date") val regDate: String,
@ColumnInfo(name = "is_done") val isDone : Boolean
) {
constructor(title: String, content:String) : this(
INVALID_ROW_ID,
title,
content,
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-DD hh:mm:ss")),
false
)
}
Entity
: Mark this data class as an entity to be handled in room storagePrimaryKey
: Indicates this member value is row id of the table.autoGenerate
: autoIncrement
@Dao
interface DaoToDo {
/**
* Takes an Entity as a parameter.
* Inserts the entity into the corresponding table in the database.
*
* @param data Instance of a Room data entity class annotated with `@Entity`
* @return new row id of the inserted entity
*/
@Insert
fun insert(data : EntityToDo) : Long
/**
* Takes a list of Entity as a parameter.
* Inserts all entity into the corresponding table in the database.
*
* @param dataList Collection of data entity class instances
* @return new row id of the inserted entity
*/
@Insert
fun insertAll(dataList : List<EntityToDo>) : List<Long>
/**
* Returns all rows in the table.
*/
@Query("SELECT id, title, content, reg_date, is_done FROM todo")
fun selectAll() : Flow<List<EntityToDo>>
/**
* Returns the row with the corresponding condition.
* @param id bind parameter for the query
*/
@Query("SELECT id, title, content, reg_date, is_done FROM todo WHERE id = :id")
fun select(id : Int) : EntityToDo
/**
* Takes an Entity as a parameter.
* Updates the row in database matching the primary key in the passed entity.
* If there's no match, no change is made.
*
* @param data only uses primary key of this entity
* @return number of rows affected
*/
@Update
fun update(data : EntityToDo) : Int
/**
* Takes an Enitiy as a parameter.
* Deletes the row in database matching the primary key in the passed entity.
* If there's no match, no change is made.
*
* @param data only uses primary key of this entity
* @return number of rows affected
*/
@Delete
fun delete(data : EntityToDo) : Int
}
Since creating database instance is not a light task, it's good practice to make it a singlton.
/**
* Main access point to the persisted data.
* Database class satisfies these conditions.
* - Annotated with '@Database' including entity array
* - Extends RoomDatabase abstract class
* - Defines each abstract method that has zero argument and returns DAO class that is associated with the database.
*/
@Database(entities = [EntityToDo::class], version = 1)
abstract class AppDataBase : RoomDatabase(){
companion object{
const val dbName = "roomToDo"
private var INSTANCE: AppDataBase? = null
fun getDatabase(context: Context) : AppDataBase{
return INSTANCE ?: synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
AppDataBase::class.java,
dbName
).build()
INSTANCE = instance
instance
}
}
}
abstract fun daoToDo() : DaoToDo
}
Converter is a class used in Android Room to convert unsupported datatypes or customize how the data is stored.
class ToDoConverter {
@TypeConverter
fun fromString(value : String?) : Boolean {
return value == "T"
}
@TypeConverter
fun fromBoolean(value : Boolean) : String{
return if(value) "T" else "F"
}
}