Migrating from LiveData to StateFlow Without UI Regressions
Teams switch to StateFlow for consistency, then accidentally break one-shot events and loading states. The migration works when you separate state streams from event streams clearly.
Step 1: map existing screen state into immutable data class
data class ScreenState(
val loading: Boolean = false,
val items: List<String> = emptyList(),
val error: String? = null
)
Step 2: expose persistent state via StateFlow
private val _state = MutableStateFlow(ScreenState())
val state: StateFlow<ScreenState> = _state
Step 3: keep one-time actions on SharedFlow
private val _events = MutableSharedFlow<UiEvent>()
val events = _events.asSharedFlow()
Pitfall
Using StateFlow for toast/navigation events. Those replay after rotation and create duplicate actions.
Verification
- Rotation preserves state without duplicate events.
- Event handling remains one-shot.
- UI tests pass across configuration changes.