← all topics03 / 05 Β· learn android

πŸ›οΈ 03 Β· learn android

MVVM Architecture

Unidirectional data flow in a UI

The View observes state; the ViewModel owns it; the repository hides the data.

MVVM β€” Model-View-ViewModel β€” is a way of structuring a screen so the rules of the UI are testable without a device, and the View is reduced to rendering. It's one of a family (MVP, MVI, MVVM) that all solve the same problem: if the interesting logic lives inside an Activity, it can't be tested except on an emulator, and it entangles business rules with Android framework code.

The core discipline is one direction of travel: the View observes state and dispatches events; it never reaches past the ViewModel to the data layer. The ViewModel holds all screen state and survives configuration changes. The repository hides where data comes from. Dependency injection wires the graph so nothing constructs its own collaborators.

The mental model

How it fits together

Unidirectional data flow

View (Activity) β€” observes StateFlow

↓

ViewModel β€” owns UiState

↓

Repository β€” single source of truth

↓

NetworkService (Retrofit)
Room / cache

the View never reaches past the ViewModel

Dependency injection

Dagger module
β†’
provides
β†’
ViewModel

nothing constructs its own collaborators

Key concepts

The ideas to internalise

Unidirectional data flow

View β†’ ViewModel (intent), ViewModel β†’ View (immutable state), ViewModel β†’ Model (repository). The View never calls the Model directly.

ViewModel

A screen's state holder. Survives rotation because the framework holds it across Activity recreation. No View reference β€” which is what makes it testable.

UiState

A sealed class (Loading / Success / Error) exposed as a StateFlow, so the UI can't render a state the data can't actually be in.

Repository

The single source of truth the ViewModel calls. It hides whether data comes from network, database, or cache.

Dependency injection

Dagger modules declare how to build deps; components declare where they're available. The ViewModel is given its repository rather than instantiating it.

StateFlow

The View collects a StateFlow<UiState> and re-renders on every emission. State is immutable and conflated β€” no partial-update bugs.

Example index

6 runnable examples

Each is a self-contained Activity + ViewModel pair you can open, read, and run.

  1. 01data/modelArticle, Source, TopHeadlinesResponse
  2. 02data/apithe Retrofit NetworkService interface
  3. 03data/repositoryTopHeadlineRepository β€” the single source of truth
  4. 04diDagger modules, components, qualifiers, scopes
  5. 05ui/baseUiState + ViewModelProviderFactory
  6. 06ui/topheadlinethe Activity, ViewModel, and Adapter

The takeaway

The rule that makes MVVM work: the View never talks to the data layer directly. It only talks to the ViewModel, which exposes immutable UiState. Dagger wires the dependencies together so nothing constructs its own collaborators β€” and a ViewModel that can't be given a fake repository can't be tested, which guts the reason MVVM exists.