Best Website for Jetpack Compose App Development

Android Jetpack Compose

Stay ahead with the latest tools, trends, and best practices in Android Jetpack Compose App development

Room Database in Jetpack Compose

Room Database in Jetpack Compose - Responsive Blogger Template
Room Database in Jetpack Compose

🏠 Room Database in Jetpack Compose — Full Practical Guide (2025)

If you’re learning Android development with Jetpack Compose, one of the most important things you’ll need is a local data storage system that works even without the internet.

That’s where Room Database comes in — a powerful, efficient, and Kotlin-friendly way to manage local structured data built on top of SQLite.


🧩 What is Room Database?

Room is an object-mapping layer over SQLite. It converts Kotlin data classes into database tables and vice versa — making data persistence simple and type-safe.

In simple terms: Room = SQLite made easy + Kotlin-friendly + lifecycle-aware.

✅ Common Use-Cases:

  • Notes or To-Do apps
  • Offline caching (store API data locally)
  • User preferences or game scores
  • Saving login info or user history

🧠 Why Use Room Instead of SQLite?

Before Room, developers used raw SQL queries and SQLiteOpenHelper classes, which were:

  • Hard to maintain
  • Error-prone
  • Not type-safe

Room solves these issues by offering:

  • Compile-time verification of SQL queries
  • Automatic mapping between Kotlin objects and tables
  • Integration with Coroutines, Flow, LiveData, ViewModel
  • Much less boilerplate code

🧱 Core Components of Room Database (Theory)

Room follows MVVM + Repository architecture. It has three key components:

ComponentDescription
EntityDefines the structure of the database table.
DAOData Access Object — defines SQL operations like insert, delete, query.
DatabaseMain class that connects Entities and DAOs.

1️⃣ Entity — Defining the Table

@Entity(tableName = "notes")
data class NoteEntity(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    val title: String,
    val content: String
)
Explanation:
  • @Entity → Marks the data class as a table.
  • @PrimaryKey(autoGenerate = true) → Auto-increment ID.
  • Each property → A column in the table.

2️⃣ DAO — Data Access Object

@Dao
interface NoteDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(note: NoteEntity)

    @Query("SELECT * FROM notes ORDER BY id DESC")
    fun getAllNotes(): Flow<List<NoteEntity>>

    @Delete
    suspend fun delete(note: NoteEntity)
}
Explanation:
  • @Insert → Add data.
  • @Query → Fetch data with SQL.
  • @Delete → Remove specific note.
  • Flow<List<NoteEntity>> → Real-time data updates for Compose.

3️⃣ Database — Connecting Everything

@Database(entities = [NoteEntity::class], version = 1)
abstract class NoteDatabase : RoomDatabase() {
    abstract fun noteDao(): NoteDao

    companion object {
        @Volatile
        private var INSTANCE: NoteDatabase? = null

        fun getInstance(context: Context): NoteDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    NoteDatabase::class.java,
                    "note_db"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}
Explanation:
  • @Database defines entities & version.
  • Singleton pattern ensures one database instance.
  • Room.databaseBuilder() creates the DB.

🧰 Repository Layer (Clean Architecture)

class NoteRepository(private val dao: NoteDao) {
    val allNotes = dao.getAllNotes()
    suspend fun insert(note: NoteEntity) = dao.insert(note)
    suspend fun delete(note: NoteEntity) = dao.delete(note)
}

This layer manages all data operations and ensures your app remains scalable.


🧠 ViewModel Integration

class NoteViewModel(application: Application) : AndroidViewModel(application) {

    private val dao = NoteDatabase.getInstance(application).noteDao()
    private val repository = NoteRepository(dao)

    val notes = repository.allNotes.asLiveData()

    fun addNote(title: String, content: String) {
        viewModelScope.launch {
            repository.insert(NoteEntity(title = title, content = content))
        }
    }

    fun delete(note: NoteEntity) {
        viewModelScope.launch {
            repository.delete(note)
        }
    }
}
Key Points:
  • viewModelScope.launch → Background thread for safe DB ops.
  • asLiveData() → Converts Flow to LiveData.
  • ViewModel survives configuration changes.

🎨 Jetpack Compose UI (Practical Implementation)

@Composable
fun NotesScreen(viewModel: NoteViewModel = viewModel()) {
    val notes by viewModel.notes.observeAsState(emptyList())
    var title by remember { mutableStateOf("") }
    var content by remember { mutableStateOf("") }

    Column(Modifier.padding(16.dp)) {
        Text("Room Database Demo", style = MaterialTheme.typography.headlineMedium)
        Spacer(Modifier.height(8.dp))

        OutlinedTextField(value = title, onValueChange = { title = it }, label = { Text("Title") })
        OutlinedTextField(value = content, onValueChange = { content = it }, label = { Text("Content") })

        Button(onClick = {
            if (title.isNotBlank() && content.isNotBlank()) {
                viewModel.addNote(title, content)
                title = ""
                content = ""
            }
        }, modifier = Modifier.padding(top = 8.dp)) {
            Text("Add Note")
        }

        Spacer(Modifier.height(16.dp))

        LazyColumn {
            items(notes) { note ->
                Card(Modifier.fillMaxWidth().padding(vertical = 4.dp)) {
                    Column(Modifier.padding(8.dp)) {
                        Text(note.title, style = MaterialTheme.typography.titleMedium)
                        Text(note.content, style = MaterialTheme.typography.bodyMedium)
                        TextButton(onClick = { viewModel.delete(note) }) {
                            Text("Delete")
                        }
                    }
                }
            }
        }
    }
}

✅ How it works:

  • User adds a note → stored in Room DB
  • Flow emits updated data automatically
  • Compose UI refreshes instantly

πŸ”„ Full Data Flow Diagram

User Input → Compose UI → ViewModel → Repository → Room DAO → SQLite Table
                                            ↑
                                            | (Flow)
                                            └─── Real-time updates back to UI

⚡ Advanced Topics (Deep Knowledge)

  • TypeConverters — store complex data like lists or dates.
  • Migrations — handle DB structure changes safely.
  • Room + Retrofit — cache API responses locally.
  • Testing — use in-memory DB for unit testing.
  • Coroutines & Flow — real-time updates without manual refresh.

🧠 Summary Table

LayerRoleExample
EntityDefines table structureNoteEntity
DAODatabase operationsNoteDao
DatabaseRoom instanceNoteDatabase
RepositoryManages data accessNoteRepository
ViewModelHolds UI dataNoteViewModel
Compose UIDisplays dataNotesScreen

🏁 Final Thoughts

Room Database is essential for modern Android apps — not just for saving data, but for creating stable, offline-capable, and reactive apps.

Combined with Jetpack Compose, Coroutines, and Flow, it gives you a clean, scalable, and future-proof architecture.

Once you master this, you can build full-fledged apps like:

  • πŸ“ Notes or To-Do apps
  • πŸ’° Expense trackers
  • πŸ“Ά Offline caching systems

Build. Learn. Repeat. You’re now ready to create your first offline-ready app using Room + Jetpack Compose 🎯

Special Message

Welcome To Coding BiharπŸ‘¨‍🏫