Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compose side effects + Jetpack navigation + onBackPressed = Stuck navigation

I am having this issue where I have to navigate when given state gets updated after an asynchronous task gets executed. I am doing it like this:

At ViewModel.kt
fun executeRandomTask() {
    viewModelScope.launch {
        runAsyncTask()
        state = Success
    }
}

At Composable.kt
LaunchedEffect(viewModel.state) {
    if(viewModel.state is Success) {
        navController.navigate("nextScreen")
    }
}

Then in the next screen, I click the back navigation button (onBackPressed) and what happens, is that the effect gets launched again. So I end up again in "nextScreen".

When I do this next workaround:

DisposableEffect(viewModel.state) {
    if(viewModel.state is Success) {
        navController.navigate("nextScreen")
    }
    onDispose {
        viewModel.state = null 
    }
}

Like this, the viewmodel state gets cleared and it also proves that what is happening is that the navigation controller destroys the previous screen (not sure if it is the intended behavior).

I am not sure about what I should be doing to avoid this, since this is a pretty common scenario and having to clear the state after a certain state is reached looks dirty.

like image 601
No Soy Beto Avatar asked Jul 01 '26 12:07

No Soy Beto


1 Answers

I use SharedFlow for emitting one-time events like this

class MyViewModel : ViewModel() {

    private val _eventFlow = MutableSharedFlow<OneTimeEvent>()
    val eventFlow = _eventFlow.asSharedFlow()

    private fun emitEvent(event: OneTimeEvent) {
        viewModelScope.launch { _eventFlow.emit(event) }
    }

}

The sealed class for defining events

sealed class OneTimeEvent {
    object SomeEvent: OneTimeEvent()
}

And finally in the Screen collect the flow like this

fun MyScreen(viewModel: MyViewModel = hiltViewModel()) {
    LaunchedEffect(Unit) {
        viewModel.eventFlow.collect { event ->
            when(event){
                SomeEvent -> { 
                    //Do Something 
                }
            }
        }
    }
}

So whenever your state changes you can emit some event and take action against it in your Screen.

like image 69
Osama Muhammad Avatar answered Jul 04 '26 03:07

Osama Muhammad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!