Thuta Learning
ProjectsMobile Developmentintermediate

Project — Todo App (CRUD + Room + ViewModel)

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Understand Project — Todo App (CRUD + Room + ViewModel) without any of the intimidation
  • Be able to run Android Studio/Compose code yourself
  • Apply this concept straight away in a real project

Let's think about it this way for a second

A real app is usually split into layers — the UI layer (Composable screens), the ViewModel layer (business logic, state management), and the Data layer (Room database, DAO). Every CRUD operation in the Todo app — adding a new todo (Create), viewing the list (Read), toggling done/undone (Update), and deleting an item (Delete) — needs to be wired through all three layers.

Let's connect this to a real scenario

Build the three layers one at a time: `TodoEntity`/`TodoDao`/`AppDatabase` (data layer) → `TodoViewModel` (observes the DAO via Flow, with add/toggle/delete functions) → `TodoListScreen`/`AddTodoScreen` (UI layer, LazyColumn + Navigation) — wire them so Navigation Compose lets you move from the list screen to the add screen.

Let's look at it together

kotlin
// Full flow: UI calls ViewModel, ViewModel calls DAO
@Composable
fun TodoListScreen(viewModel: TodoViewModel = hiltViewModel(), onAddClick: () -> Unit) {
    val todos by viewModel.todos.collectAsState()

    Scaffold(
        floatingActionButton = {
            FloatingActionButton(onClick = onAddClick) { Icon(Icons.Default.Add, null) }
        }
    ) { padding ->
        LazyColumn(modifier = Modifier.padding(padding)) {
            items(todos) { todo ->
                Row {
                    Checkbox(
                        checked = todo.isDone,
                        onCheckedChange = { viewModel.toggleDone(todo.id) }
                    )
                    Text(todo.title)
                    IconButton(onClick = { viewModel.delete(todo.id) }) {
                        Icon(Icons.Default.Delete, null)
                    }
                }
            }
        }
    }
}
You should see
Run the Todo app and you should be able to add a todo, toggle it done/undone, delete it, and see the data still there after restarting the app.

Try it in 5 minutes

Build the whole Todo app yourself using the three layers (Data/ViewModel/UI) — verify all four CRUD operations work on the emulator.

One thing to watch out for

If you delete a todo item permanently with no 'undo' option, that's rough on the user — consider adding a Snackbar with an 'Undo' button instead.

Easy traps

  • Deleting an item instantly with no confirmation dialog — an accidental tap can wipe out data
  • Leaving the empty state (when the todo list has nothing in it) unhandled and just showing a blank screen — apps with good UX usually show a 'No todos yet' message instead

Now try it yourself

Build the whole Todo app yourself using the three layers (Data/ViewModel/UI) — verify all four CRUD operations work on the emulator.

You'll know it worked when: Run the Todo app and you should be able to add a todo, toggle it done/undone, delete it, and see the data still there after restarting the app.

Project — Todo App (CRUD + Room + ViewModel) | Thuta Learning