0
0
Android Kotlinmobile~20 mins

Room with Flow for reactive data in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: User List
Displays a list of users stored in a local Room database. The list updates automatically when data changes using Kotlin Flow.
Target UI
---------------------
| User List         |
---------------------
| - Alice           |
| - Bob             |
| - Charlie         |
---------------------
| [Add User Button] |
---------------------
Use Room database to store User entities with id and name
Create a DAO that returns Flow<List<User>> for all users
Observe the Flow in the UI to update the list reactively
Add a button to insert a new user with a random name
Display the list of users in a vertical scrollable list
Starter Code
Android Kotlin
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

@Entity
 data class User(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val name: String
)

@Dao
interface UserDao {
    // TODO: Define function to get all users as Flow<List<User>>

    // TODO: Define function to insert a 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()) {
                    // TODO: Implement UserListScreen composable
                }
            }
        }
    }
}
Task 1
Task 2
Task 3
Task 4
Task 5
Task 6
Solution
Android Kotlin
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.

Final Result
Completed Screen
---------------------
| User List         |
---------------------
| - User123         |
| - User456         |
| - User789         |
---------------------
| [Add User Button] |
---------------------
When the app starts, the list shows all users from the database.
Tapping 'Add User' inserts a new user with a random name.
The list updates automatically to show the new user without refreshing.
Stretch Goal
Add a swipe-to-delete feature to remove users from the list.
💡 Hint
Use Compose's SwipeToDismiss with a coroutine to call a suspend delete function in UserDao.