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
RoomSingleton
class 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
Student
data 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
LazyColumn
and 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
- jetpack compose - IconButton from vector resource