ViewModel & State Management

June 02, 2026 1 min read

UI logic and data should live in a ViewModel, not the Activity/Fragment. ViewModels survive configuration changes (like rotation) and make code testable.

A ViewModel exposing state

class CounterViewModel : ViewModel() {
    private val _count = MutableStateFlow(0)
    val count: StateFlow<Int> = _count

    fun increment() { _count.value++ }
}

Observing it

// Compose
val vm: CounterViewModel = viewModel()
val count by vm.count.collectAsState()
Text("$count")

// XML world: LiveData + observe(viewLifecycleOwner) { ... }

The pattern

  • View tells the ViewModel about events (button clicks).
  • ViewModel updates state and exposes it.
  • View renders whatever the state currently is.
Common mistake: Never hold a reference to a View or Context (except applicationContext) in a ViewModel — it causes memory leaks.

Summary

ViewModels hold UI state that survives rotation. Expose immutable state (StateFlow/LiveData) and mutate it only inside the ViewModel.