Jetpack Compose - Room Add, Remove, Update
This code demonstrates a basic Android application built with Jetpack Compose that utilizes Room for data persistence. The app manages a list of "Students" with functionalities to add, remove, and update them.
Key Components:
- Room Database: The 
RoomSingletonclass defines a Room database with a single entity -Student. It provides methods to access the DAO (Data Access Object) for interacting with student data. - Student Entity: The 
Studentdata class represents a student record with properties like ID (primary key), name (full name), and result (integer). - StudentDao: This interface defines methods for CRUD (Create, Read, Update, Delete) operations on student data within the database.
 - StudentViewModel: This ViewModel class acts as the single source of truth for student data. It holds a reference to the Room database instance and exposes functions to interact with students (insert, update, delete, clear all).
 - MainContent Composable: This function represents the UI of the app. It displays a list of students using 
LazyColumnand provides buttons for adding new students, clearing all students, editing individual students, and deleting them. 
Summary
This example showcases how to integrate Jetpack Compose with Room to manage data in an Android application. It demonstrates live data updates, user interaction with the UI to manipulate data, and background operations using coroutines for database access. This provides a starting point for building more complex applications with persistent data storage and a reactive UI.
MainActivity.kt
package com.example.composeroomexample
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import java.util.*
import kotlin.random.Random
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { MainContent() }
    }
}
@Composable
fun MainContent(){
    val scope = rememberCoroutineScope()
    val model = viewModel<StudentViewModel>()
    val list:List<Student> = model.students.observeAsState(listOf()).value
    Column(
        modifier = Modifier.padding(12.dp),
        verticalArrangement = Arrangement.spacedBy(12.dp)
    ) {
        Row(
            horizontalArrangement = Arrangement.spacedBy(12.dp)
        ){
            // add new student
            Button(onClick = {
                model.insert(
                    Student(
                        null,UUID.randomUUID().toString(),
                        Random.nextInt(10,90)
                    )
                )
            }) { Text(text = "Add Student") }
            // delete all students
            Button(onClick = { model.clear() }) {
                Text(text = "Clear")
            }
        }
        LazyColumn(
            verticalArrangement = Arrangement.spacedBy(8.dp),
            contentPadding = PaddingValues(vertical = 12.dp)
        ) {
            itemsIndexed(list) { index,item ->
                Card(
                    modifier = Modifier.fillMaxWidth(),
                    backgroundColor = Color(0xFFA1CAF1)
                ) {
                    Row(
                        modifier = Modifier.padding(12.dp),
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Box(
                            Modifier.size(48.dp).clip(CircleShape)
                                .background(Color(0xFFF0FFFF)),
                            contentAlignment = Alignment.Center
                        ) {
                            Text(
                                text = "${item.id}",
                                style = MaterialTheme.typography.h6
                            )
                        }
                        Spacer(modifier = Modifier.width(12.dp))
                        Text(
                            text = item.fullName.take(10),
                            style = MaterialTheme.typography.caption
                        )
                        Spacer(modifier = Modifier.width(12.dp))
                        Text(
                            text = " ${item.result}",
                            style = MaterialTheme.typography.h5
                        )
                        Spacer(modifier = Modifier.weight(1F))
                        // edit button
                        IconButton(onClick = {
                            val updatedItem = Student(
                                item.id,item.fullName,Random.nextInt(0,100)
                            )
                            model.update(updatedItem)
                        }) { Icon(Icons.Filled.Edit,"")}
                        // delete button
                        IconButton(onClick = { model.delete(item)}) {
                            Icon(Icons.Filled.Delete,"")
                        }
                    }
                }
            }
        }
    }
}
RoomSingleton.kt
package com.example.composeroomexample
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context
@Database(entities = [Student::class], version = 1, exportSchema = false)
abstract class RoomSingleton : RoomDatabase() {
    abstract fun studentDao():StudentDao
    companion object {
        private var INSTANCE: RoomSingleton? = null
        fun getInstance(context: Context): RoomSingleton {
            if (INSTANCE == null) {
                INSTANCE = Room.databaseBuilder(
                    context,
                    RoomSingleton::class.java,
                    "roomdb")
                    .build()
            }
            return INSTANCE as RoomSingleton
        }
    }
}
RoomEntity.kt
package com.example.composeroomexample
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "studentTbl")
data class Student(
    @PrimaryKey
    var id:Long?,
    @ColumnInfo(name = "uuid")
    var fullName: String,
    @ColumnInfo(name = "result")
    var result:Int
)
RoomDao.kt
package com.example.composeroomexample
import androidx.lifecycle.LiveData
import androidx.room.*
@Dao
interface StudentDao{
    @Query("SELECT * FROM studentTbl ORDER BY id DESC")
    fun getStudents():LiveData<MutableList<Student>>
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(student:Student)
    @Update
    suspend fun update(student:Student)
    @Delete
    suspend fun delete(student:Student)
    @Query("DELETE FROM studentTbl")
    suspend fun clear()
}
StudentViewModel.kt
package com.example.composeroomexample
import android.app.Application
import androidx.lifecycle.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class StudentViewModel(application:Application)
    : AndroidViewModel(application){
    
	private val db:RoomSingleton = RoomSingleton
        .getInstance(application)
    internal val students : LiveData<MutableList<Student>> =
        db.studentDao().getStudents()
    fun insert(student: Student){
        viewModelScope.launch(Dispatchers.IO) {
            db.studentDao().insert(student)
        }
    }
    fun update(student: Student){
        viewModelScope.launch(Dispatchers.IO) {
            db.studentDao().update(student)
        }
    }
    fun delete(student: Student){
        viewModelScope.launch(Dispatchers.IO) {
            db.studentDao().delete(student)
        }
    }
    fun clear(){
        viewModelScope.launch(Dispatchers.IO) {
            db.studentDao().clear()
        }
    }
}
build.gradle [dependencies]
apply plugin: 'kotlin-kapt'
dependencies {
    def room_version = "2.4.2"
    implementation "androidx.room:room-runtime:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    kapt "androidx.room:room-compiler:$room_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0-alpha06"
    implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.0-alpha06'
    implementation 'androidx.compose.runtime:runtime-livedata:1.2.0-alpha07'
}
- jetpack compose - How to use WebView
 - jetpack compose - WebView ProgressIndicator
 - jetpack compose - WebView progress percentage
 - jetpack compose - Backdrop scaffold
 - jetpack compose - Double click listener
 - jetpack compose - Long click listener
 - jetpack compose - Pass onClick event to function
 - jetpack compose - TabRow custon indicator
 - jetpack compose - Get primary language
 - jetpack compose - Get screen orientation
 - jetpack compose - How to change StatusBar color
 - jetpack compose - How to change NavigationBar color
 - jetpack compose - How to change SystemBars color
 - jetpack compose - Icon from vector resource