0
0
Android Kotlinmobile~20 mins

Room with Coroutines in Android Kotlin - Mini App: Build & Ship

Choose your learning style9 modes available
Build: Notes List
A simple screen to display a list of notes stored in a Room database using Kotlin Coroutines for asynchronous operations.
Target UI
-------------------------
|       Notes List       |
-------------------------
| - Note 1               |
| - Note 2               |
| - Note 3               |
|                       |
| [+] Add Note           |
-------------------------
Use Room database to store notes with id and text fields.
Use Kotlin Coroutines to fetch notes asynchronously.
Display notes in a vertical list.
Add a FloatingActionButton with '+' icon to add a new note.
When '+' is tapped, add a new note with sample text to the database and refresh the list.
Starter Code
Android Kotlin
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            NotesScreen()
        }
    }
}

@Composable
fun NotesScreen() {
    // TODO: Implement UI and data loading
}
Task 1
Task 2
Task 3
Task 4
Task 5
Solution
Android Kotlin
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import androidx.room.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@Entity(tableName = "notes")
data class Note(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val text: String
)

@Dao
interface NoteDao {
    @Query("SELECT * FROM notes")
    suspend fun getAll(): List<Note>

    @Insert
    suspend fun insert(note: Note)
}

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

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

        fun getInstance(context: android.content.Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "notes_db"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

class MainActivity : ComponentActivity() {
    private lateinit var db: AppDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        db = AppDatabase.getInstance(this)

        setContent {
            NotesScreen(db)
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NotesScreen(db: AppDatabase) {
    var notes by remember { mutableStateOf<List<Note>>(emptyList()) }
    val scope = rememberCoroutineScope()

    LaunchedEffect(Unit) {
        notes = withContext(Dispatchers.IO) {
            db.noteDao().getAll()
        }
    }

    Scaffold(
        floatingActionButton = {
            FloatingActionButton(
                onClick = {
                    scope.launch(Dispatchers.IO) {
                        db.noteDao().insert(Note(text = "New note"))
                        val updatedNotes = db.noteDao().getAll()
                        withContext(Dispatchers.Main) {
                            notes = updatedNotes
                        }
                    }
                },
                containerColor = MaterialTheme.colorScheme.primary
            ) {
                Icon(Icons.Default.Add, contentDescription = "Add Note")
            }
        },
        content = { paddingValues ->
            LazyColumn(
                modifier = Modifier
                    .fillMaxSize()
                    .padding(paddingValues)
                    .padding(16.dp)
            ) {
                items(notes) { note ->
                    Text(text = note.text, modifier = Modifier.padding(vertical = 8.dp))
                    Divider()
                }
            }
        }
    )
}

This solution uses Room to store notes with an id and text. The NoteDao interface defines suspend functions to get all notes and insert a new note, which allows using Kotlin Coroutines for asynchronous database operations.

The AppDatabase singleton provides the Room database instance.

In MainActivity, the database instance is created and passed to the NotesScreen composable.

The NotesScreen composable uses remember and mutableStateOf to hold the list of notes. It loads notes asynchronously on launch with LaunchedEffect and updates the UI.

The FloatingActionButton adds a new note asynchronously on click, then reloads the notes and updates the UI on the main thread.

This approach keeps the UI responsive and follows Android best practices for Room and Coroutines.

Final Result
Completed Screen
-------------------------
|       Notes List       |
-------------------------
| New note               |
| New note               |
| New note               |
|                       |
| [+] Add Note           |
-------------------------
User sees a list of notes with their text.
User taps the '+' button to add a new note.
A new note with text 'New note' appears at the bottom of the list.
Stretch Goal
Add a text input dialog to enter custom note text before adding it to the database.
💡 Hint
Use Compose AlertDialog with TextField and buttons to get user input, then insert the note with that text.