In Android I often want to navigate is response to state change from a ViewModel. (for example, successful authentication triggers navigation to the user's home screen.)
Is the best practice to trigger navigation from within the ViewModel? Is there an intentional mechanism to trigger navigation within a composable in response to a ViewModel state change?
With Jetpack Compose the process for handling this use case is not obvious. If I try something like the following example navigation will occur, but the destination I navigate to will not behave correctly. I believe this is because the original composable function was not allowed to finish before navigation was invoked.
// Does not behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
navController.navigate("/gameScreen")
} else {
LoginScreen()
}
}
I do observe the correct behavior if I use LauncedEffect as follows:
// Does behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
LaunchedEffect(key1 = "test") {
navController.navigate("$/gameScreen")
}
} else {
LoginScreen()
}
}
Is this correct? The documentation for LaunchedEffect states the following, but the meaning is not 100% clear to me:
When LaunchedEffect enters the composition it will launch block into the composition's CoroutineContext. The coroutine will be cancelled and re-launched when LaunchedEffect is recomposed with a different key1, key2 or key3. The coroutine will be cancelled when the LaunchedEffect leaves the composition.