Android Room Database¶
Room is Android's SQLite abstraction layer that provides compile-time SQL verification, LiveData integration, and coroutine support. It maps Kotlin data classes to database tables with annotations.
Key Facts¶
- Room has three core components: Entity (table), DAO (queries), Database (holder)
@Entityannotates data classes to define database tables@Daointerface defines CRUD operations with SQL annotations- Returning
LiveData<T>from DAO queries auto-updates observers when data changes - Database class is a singleton using
companion object+synchronized+@Volatile fallbackToDestructiveMigration()recreates DB on schema change (loses data)kaptannotation processor generates Room implementation code at compile time
Patterns¶
Entity (Table Model)¶
import androidx.room.*
@Entity(tableName = "recording_table")
data class RecordingItem(
@PrimaryKey(autoGenerate = true)
val id: Long = 0L,
@ColumnInfo(name = "name")
var name: String = "",
@ColumnInfo(name = "filePath")
var filePath: String = "",
@ColumnInfo(name = "length")
var length: Long = 0L,
@ColumnInfo(name = "time")
var time: Long = 0L
)
DAO (Data Access Object)¶
import androidx.lifecycle.LiveData
import androidx.room.*
@Dao
interface RecordDatabaseDao {
@Insert
fun insert(record: RecordingItem)
@Update
fun update(record: RecordingItem)
@Query("SELECT * FROM recording_table WHERE id = :key")
fun getRecord(key: Long?): RecordingItem?
@Query("DELETE FROM recording_table WHERE id = :key")
fun removeRecord(key: Long?)
@Query("DELETE FROM recording_table")
fun clearAll()
@Query("SELECT * FROM recording_table ORDER BY id DESC")
fun getAllRecords(): LiveData<MutableList<RecordingItem>>
@Query("SELECT COUNT(*) FROM recording_table")
fun getCount(): LiveData<Int>
}
Returning LiveData<T> from queries - Room automatically runs the query on a background thread and updates observers when data changes.
Database Class (Singleton)¶
import androidx.room.*
@Database(
entities = [RecordingItem::class],
version = 1,
exportSchema = false
)
abstract class RecordDatabase : RoomDatabase() {
abstract val recordDatabaseDao: RecordDatabaseDao
companion object {
@Volatile
private var INSTANCE: RecordDatabase? = null
fun getInstance(context: Context): RecordDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
RecordDatabase::class.java,
"record_app_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
Using Room from ViewModel¶
class RecordViewModel(app: Application) : AndroidViewModel(app) {
private val database = RecordDatabase.getInstance(app).recordDatabaseDao
val allRecords = database.getAllRecords()
fun insertRecord(item: RecordingItem) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
database.insert(item)
}
}
}
fun deleteRecord(key: Long) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
database.removeRecord(key)
}
}
}
}
Room vs SwiftData/Core Data Comparison¶
| Feature | Room (Android) | SwiftData (iOS 17+) | Core Data (iOS) |
|---|---|---|---|
| Model | @Entity data class | @Model class | NSManagedObject |
| Queries | @Dao interface + SQL | @Query property wrapper | @FetchRequest |
| Reactive | LiveData<T> | Auto-updates view | FetchedResults<T> |
| Setup | Singleton + Builder | .modelContainer() | NSPersistentContainer |
build.gradle Dependencies¶
implementation "androidx.room:room-runtime:2.5.0"
kapt "androidx.room:room-compiler:2.5.0"
implementation "androidx.room:room-ktx:2.5.0" // coroutine support
Gotchas¶
fallbackToDestructiveMigration()deletes ALL data on schema version change - useaddMigrations()with SQL ALTER TABLE for production- DAO operations (except LiveData queries) must run on background threads - use
Dispatchers.IO @Volatileon INSTANCE is critical - without it, different threads may see stale cached valuessynchronized(this)prevents race conditions when multiple threads try to create the database simultaneously- Room validates SQL queries at compile time - syntax errors cause build failures, not runtime crashes
exportSchema = falsesuppresses the schema export warning - set totrueand provide export directory for migration support
See Also¶
- android mvvm architecture - ViewModel + LiveData consuming Room data
- kotlin android fundamentals - Kotlin basics, data class, companion object
- android retrofit networking - fetching remote data to store in Room