Home > front end >  Why does Android Jetpack Compose snapShotFlow re emit last value on configuration change
Why does Android Jetpack Compose snapShotFlow re emit last value on configuration change

Time:11-22

My current Android Jetpack Compose application employs snapShotFlow to convert mutableStateOf() to flow and trigger user actions as follows

In ViewModel:-

var displayItemState by mutableStateOf(DisplayItemState())


@Immutable
data class DisplayItemState(
    val viewIntent: Intent? = null
)

In composable:-

val displayItemState = viewModel.displayItemState

LaunchedEffect(key1 = displayItemState) {
    snapshotFlow { displayItemState }
        .distinctUntilChanged()
        .filter { it.viewIntent != null }
        .collectLatest { displayItemState ->
            context.startActivity(displayItemState.viewIntent)
        }
}

everything works as expected while I keep my test device in portrait or landscape.

However when I change the device orientation the last collected snapShotFlow value is resent.

If I reset the displayItemState as follows in the snapShotFlow this fixes the issue however this feels like the wrong fix. What am i doing wrong? what is the correct approach to stop the snapShotFlow from re triggering on orientation change

val displayItemState = viewModel.displayItemState

LaunchedEffect(key1 = displayItemState) {
    snapshotFlow { displayItemState }
        .distinctUntilChanged()
        .filter { it.viewIntent != null }
        .collectLatest { displayItemState ->
            context.startActivity(displayItemState.viewIntent)
            viewModel.displayItemState = DisplayItemState()
        }
}

CodePudding user response:

That's intended behavior, you are not doing anything wrong. Compose's (Mutable)State holds the last value, similarly to StateFlow, so new collection from them always starts with the last value.

Your solution is ok, something very similar is actually recommended in Android's app architecture guide here:

For example, when showing transient messages on the screen to let the user know that something happened, the UI needs to notify the ViewModel to trigger another state update when the message has been shown on the screen.

Another possibility would be to use SharedFlow instead of MutableState in your viewModel - SharedFlow doesn't keep the last value so there won't be this problem.

  • Related