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.

Get New Tutorials by Email

No spam. Just clear, practical breakdowns you can apply right away.

Enjoy this tutorial?

Get new practical tech tutorials in your inbox.