import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.room.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import kotlin.random.Random
@Entity
data class User(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val name: String
)
@Dao
interface UserDao {
@Query("SELECT * FROM User")
fun getAllUsers(): Flow<List<User>>
@Insert
suspend fun insertUser(user: User)
}
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "app-db"
).build()
val userDao = db.userDao()
setContent {
MaterialTheme {
Surface(modifier = Modifier.fillMaxSize()) {
UserListScreen(userDao)
}
}
}
}
}
@androidx.compose.runtime.Composable
fun UserListScreen(userDao: UserDao) {
val usersFlow = userDao.getAllUsers()
val users by usersFlow.collectAsState(initial = emptyList())
val scope = rememberCoroutineScope()
Column {
LazyColumn(modifier = Modifier.weight(1f)) {
items(users) { user ->
Text(text = "- ${user.name}")
}
}
Button(onClick = {
scope.launch {
val randomName = "User${Random.nextInt(1000)}"
userDao.insertUser(User(name = randomName))
}
}) {
Text("Add User")
}
}
}
This solution uses Room to store User entities with an auto-generated id and a name.
The UserDao interface defines getAllUsers() which returns a Flow<List<User>>. This allows the UI to observe the database reactively.
The insertUser suspend function inserts a new user.
In MainActivity, we build the Room database and get the DAO instance.
The UserListScreen composable collects the Flow as state, so the UI updates automatically when the data changes.
Users are displayed in a scrollable list using LazyColumn. A button below adds a new user with a random name when clicked, launching a coroutine to call the suspend insert function.
This setup demonstrates reactive data flow from Room to UI using Kotlin Flow and Compose.