I have implemented method to manage single-time events in android compose, like displaying snackbar, according to this article by Marco Cattaneo on medium.com.
It uses channel of messages in viewmodel. Inserting messages in this channel should fire one-time event in compose and dispaly snackbar. There is an LaunchedEffects and channel.collect used in composable function to display snackbar.
But I have problem, that snackbar is not displayed if recomposition happens after firing snackbar. When I make change in uiState and send new message to channel in same time, Snackbar is not displayed because recomposition destroys it immediately. If I change uiState and send new message to channel with some delay (500 miliseconds), snackbar is disaplyed just fine, because all recompositions are already done.
Is there any way to prevent snackbars from being destroyed by recompositions? Toast messages works just fine. I have problem only with snackbars.
Viewmodel:
...
private val _uiState: MutableStateFlow<UiStateClass> = MutableStateFlow(UiStateClass())
val uiState: StateFlow<UiStateClass> get() = _uiState.asStateFlow()
private val _snackMessage = Channel<String>(capacity = Channel.BUFFERED)
val snackMessage: Flow<String>
get() = _snackMessage.receiveAsFlow()
...
View:
@Composable
fun MyScreen(
viewModel: MyViewModel,
) {
val uiState by viewModel.uiState.collectAsState()
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
) { innerPadding ->
// Main part of user interface
ScreenContent(
uiState
...
)
val lifecycleOwner = LocalLifecycleOwner.current
val context = LocalContext.current
// Displaying snackbar
LaunchedEffect(viewModel.snackMessage) {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.snackMessage.collect { msg ->
snackbarHostState.showSnackbar(msg)
}
}
}
}
}
}
If I insert something only into _snackMessage in viewmodel, snackbar is displayed correctly. If I change uiState and insert something into _snackMessage in same time, snackbar is not displayed. If I change uiState and insert something into _snackMessage with delay(500), snackbar is displayed.