Handling Transient Messages With Unidirectional Data Flow
Handling Transient Messages With Unidirectional Data Flow
Transient UI messages like Snackbars often originate from ViewModel logic, such as a failed network request or a completed action. In a Unidirectional Data Flow (UDF) architecture, these messages should be represented as part of the UI state rather than fired as one-off events. The ViewModel sets the message in state, the UI observes and displays it, and then notifies the ViewModel to clear it. By the end of this lesson, you will be able to:
- Explain why transient messages should be modeled as UI state rather than one-off events.
- Implement a Snackbar display using a nullable
userMessageproperty in the UI state. - Describe the consumption cycle: ViewModel sets state, UI displays, UI notifies, ViewModel clears.
- Identify the risks of using
ChannelorSharedFlowfor transient UI events. - Apply
LaunchedEffectto display a Snackbar when the message state changes.
Why State, Not Events
In UDF, the UI is a function of its state. If a Snackbar needs to appear, the state should reflect that. Modeling the message as a nullable property in the UI state data class ensures that:
- The message survives configuration changes because the state is preserved in the ViewModel.
- The UI always renders what the state dictates, making behavior reproducible.
- There is no risk of losing the message if the UI is not collecting at the moment the event fires.
One-off event mechanisms like Channel or SharedFlow introduce timing dependencies. If the UI is not actively collecting when the event is emitted, the event can be lost. If multiple collectors exist, the event might be consumed by the wrong one. Representing the message as state eliminates these problems.
The Consumption Cycle
The cycle has four steps:
- The ViewModel updates the
userMessageproperty in its UI state with the message text. - The UI collects the state. When
userMessageis not null, it triggers Snackbar display. - After the Snackbar is shown and dismissed, the UI calls
userMessageShown()on the ViewModel. - The ViewModel sets
userMessageback to null, preventing the Snackbar from reappearing on recomposition.
Implementation
The UI state includes a nullable message field:
data class LatestNewsUiState(
val news: List<NewsItemUiState> = emptyList(),
val isLoading: Boolean = false,
val userMessage: String? = null
)
This interview continues for subscribers
Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.
Become a Sponsor