What it is
Room is Android's persistence library, providing a typed abstraction over SQLite with compile-time query verification and Flow observation.
Entities describe tables, DAOs declare queries, and a Database class ties them together. Queries returning Flow emit again whenever the underlying data changes.
Installation
implementation("androidx.room:room-runtime:2.6.1")Getting started
The smallest useful thing you can do with it, and what each part means.
kotlin
@Entity(tableName = "books", indices = [Index("year")])
data class BookEntity(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val title: String,
val year: Int,
)
@Dao
interface BookDao {
// Verified against the schema at compile time.
@Query("SELECT * FROM books WHERE year >= :minYear ORDER BY year DESC")
fun observeSince(minYear: Int): Flow<List<BookEntity>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun upsert(book: BookEntity)
@Query("DELETE FROM books WHERE id = :id")
suspend fun delete(id: Int)
}Advanced usage
Where the library earns its place over a simpler alternative.
kotlin
val MIGRATION_1_2 = object : Migration(1, 2) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE books ADD COLUMN isbn TEXT")
}
}
Room.databaseBuilder(context, AppDatabase::class.java, "app.db")
.addMigrations(MIGRATION_1_2)
// Never ship fallbackToDestructiveMigration — it deletes user data.
.build()
data class BookWithAuthor(
@Embedded val book: BookEntity,
@Relation(parentColumn = "authorId", entityColumn = "id")
val author: AuthorEntity,
)
@Transaction
@Query("SELECT * FROM books")
fun observeWithAuthors(): Flow<List<BookWithAuthor>>Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Room cannot verify the data integrity
- The schema changed without a migration. Add a Migration for the version bump.
- Cannot access database on the main thread
- A synchronous DAO method was called on the UI thread. Make it suspend or return Flow.
Best practices
- Write real migrations; fallbackToDestructiveMigration silently wipes user data.
- Export the schema JSON and commit it so migrations can be tested.
- Return Flow for anything the UI observes, and suspend for one-off reads and writes.
- Add @Transaction to queries that assemble relations.
Background
Why it exists, and what it was reacting to.
Room replaced hand-written SQLiteOpenHelper code. Its defining feature is that it parses every @Query at compile time against the schema, so a mistyped column fails the build.
