Local Persistence (Room + Flow)
Room: Entities, DAO & Reactive Queries
Room is the recommended SQLite abstraction. Define an `@Entity` (table), a `@Dao` (queries), and a `@Database`. Returning `Flow` from a query makes the UI update automatically whenever the data changes.
๐ Explanation
Room generates the SQLite boilerplate at compile time and verifies your SQL. `@Entity` maps to a table, `@Dao` declares typed queries, and `@Database` ties them together. Writes use `suspend` functions (off the main thread); reads that return `Flow` are observable โ Room re-runs the query and emits a new list whenever the table changes, so your Compose UI stays in sync automatically.
Note: Code execution is not available for Android/Kotlin in the browser. Use Android Studio to run and test the app.
import androidx.room.*import kotlinx.coroutines.flow.Flow// 1. The table@Entity(tableName = "notes")data class NoteEntity(@PrimaryKey(autoGenerate = true) val id: Long = 0,val title: String,val body: String,val updatedAt: Long)// 2. The queries (suspend for writes, Flow for reactive reads)@Daointerface NoteDao {@Query("SELECT * FROM notes ORDER BY updatedAt DESC")fun observeNotes(): Flow<List<NoteEntity>> // emits on every change@Insert(onConflict = OnConflictStrategy.REPLACE)suspend fun upsert(note: NoteEntity)@Deletesuspend fun delete(note: NoteEntity)}// 3. The database@Database(entities = [NoteEntity::class], version = 1)abstract class AppDatabase : RoomDatabase() {abstract fun noteDao(): NoteDao}// 4. Consuming reactively in a ViewModelclass NotesViewModel(dao: NoteDao) : ViewModel() {val notes = dao.observeNotes().stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())}