StateFlow: A Hot Flow for UI State

StateFlow is a state-holder observable that emits the current and new state updates to its collectors. Use it to expose UI state from a ViewModel to a UI. The footgun: slow collectors can miss intermediate state updates, receiving only the most recent value.
WHY IT EXISTS: Android apps need a robust way to pass state from business logic (like in a ViewModel) to the UI. Early solutions like LiveData were tied to the Android framework. StateFlow was created as a pure Kotlin, coroutine-native solution for modern, lifecycle-aware state management.
THE MENTAL MODEL: Think of StateFlow as a public bulletin board displaying a single, official announcement. Anyone can walk up and read the current announcement at any time. You can also choose to watch the board, and you'll be notified the moment a new announcement is posted, replacing the old one. The board is always active and always shows something, even if no one is looking.
HOW IT WORKS: StateFlow is a specialized, hot SharedFlow that requires an initial value. You create a private MutableStateFlow to hold and update the state, and expose it publicly as an immutable StateFlow. When you update the .value property of the MutableStateFlow, it emits the new state to all active collectors. A new collector immediately receives the current value. By default, StateFlow only emits if the new value is not equal to the old one, preventing redundant updates.
WHEN TO USE IT: Use StateFlow to represent observable state that has a single source of truth. It is the primary choice for exposing UI state from a ViewModel to a Jetpack Compose UI or an Activity/Fragment. Its integration with coroutine scopes makes handling UI lifecycles clean and simple.
WHEN NOT TO USE IT: Do not use StateFlow for one-shot events that must be processed exactly once, like showing a Snackbar or navigating. Because it's state-oriented, a configuration change (like screen rotation) could cause the UI to re-collect the last state and trigger the event again. For events, a Channel is a more appropriate tool.
ONE CANONICAL EXAMPLE: A ViewModel for a login screen can expose its state. First, define the mutable state holder: private val _uiState = MutableStateFlow<LoginState>(LoginState.Idle). Then, expose it as an immutable flow: val uiState: StateFlow<LoginState> = _uiState.asStateFlow(). The UI collects viewModel.uiState. When the user clicks login, the ViewModel updates the value via _uiState.value = LoginState.Loading, and the UI automatically shows a progress spinner.
Read the original → developer.android.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.