I have a Login screen and a Home screen. When I st...
# compose
l
I have a Login screen and a Home screen. When I start the app, I check the login state and if the user is logged in, navigate with navController to the Home screen.
Copy code
setContent {
    val navigateToHomeScreen by viewModel.navigateToHomeScreen.collectAsStateWithLifecycle()
    if (navigateToHomeScreen) {
        navController.navigate(HOME) {
            popUpTo(LOGIN) { inclusive = true }
    }
}
However when I close the app with the back button and then reopen, it crashes with
Copy code
java.lang.IllegalArgumentException: Cannot navigate to shoppingSessions. Navigation graph has not been set for NavController androidx.navigation.internal.NavControllerImpl
n
show me all code
l
The rest is just the navigation graph
Copy code
NavHost(navController, startDestination = LOGIN) {
    composable(HOME) {
        HomeScreen( /* ... */)
    }

    composable(LOGIN) {
        LoginScreen( /* ... */)
    }
}
It uses the same
navController
instance, which is remembered beforehand.
This must be some race condition, because the navigation takes place before the nav graph got composed.
I tried wrapping the navigation in a
SideEffect
, but then it doesn't navigate at all.
n
You need to make sure you are setting the navigation graph to your
NavController
before navigating anywhere.
Ensure that your
NavHost
is set before you trigger any navigation
val navController = rememberNavController() NavHost( navController = navController, startDestination = "home", // or your actual start ) { composable("home") { HomeScreen(navController) } composable("shoppingSessions") { ShoppingSessionScreen() } }
Then in your composable, do navController.navigate("shoppingSessions")
Make sure you don’t call
navigate()
before
NavHost
is rendered
Are you navigating after the composition lifecycle?
l
How do I make sure of it?
Note however, then I don't navigate inside the
composable
The navigation is outside of NavHost, it just reacts to a viewModel uiState change
Copy code
setContent {
    val navController = rememberNavController()

    val navigateToHomeScreen by viewModel.navigateToHomeScreen.collectAsStateWithLifecycle()

    if (navigateToHomeScreen) {
        viewModel.onNavigatedToHomeScreen() // resets the state
        navController.navigate(HOME) {
            popUpTo(LOGIN) { inclusive = true }
        }
    }

    NavHost(navController, startDestination = LOGIN) {
        composable(HOME) {
            HomeScreen( /* ... */)
        }

        composable(LOGIN) {
            LoginScreen( /* ... */)
        }
    }
}
n
setContent { val navController = rememberNavController() val navigateToHomeScreen by viewModel.navigateToHomeScreen.collectAsStateWithLifecycle() if (navigateToHomeScreen) { viewModel.onNavigatedToHomeScreen() // resets the state navController.navigate(HOME) { popUpTo(LOGIN) { inclusive = true } } } NavHost(navController, startDestination = LOGIN) { composable(HOME) { HomeScreen( /* ... */) } composable(LOGIN) { LoginScreen( /* ... */) } } } all code is in same file ?
l
Yes
It's the
setContent
Method
Inside the Activity's
onCreate()
n
could you tell me where the Navigation graph ?
l
It's in the code
n
before NavHost you are doing to navigate() that why you are getting error
val navController = rememberNavController() after navcontroller use navHost whereas you are using to navigate(HOME)
l
Thank you, looks like it helped!
However now it opens a new screen on top of the old one every time. Maybe you know how to fix it as well?
launchSingleTop = true
inside the
navigate()
didn't help
n
navigate() issue fixed ?
l
Yes
n
popUpTo("shoppingSessions") { inclusive = true }
use this code instant of launchSingleTop = true
l
Then the login screen shows when navigating back
n
also use this code launchSingleTop = true
l
It doesn't change anything, the login screen is still shown
I have to
Copy code
popUpTo(LOGIN) { inclusive = true }
n
show me clear issue
l
The issue is that when navigating back from shopping sessions (home) the login is shown
n
i didn't understand about new screen or login screen
l
When the user navigates with the back button
There is login screen, and there is home (shopping sessions) screen
When the automatic login in viewModel is successful, the shopping sessions should be shown automatically.
But when the user then navigates with the back button from the shopping sessions screen, then the login screen should not be shown anymore
n
so you should show login screen after back button ?
l
No
It should be removed from the back stack
n
show me your navigate("shoppingSessions") code
after login you are going to shopping page . use below code navController.navigate("shoppingSessions") { popUpTo("login") { inclusive = true // This removes login from back stack } launchSingleTop = true }
replace your code
l
Copy code
if (navigateToShoppingSessions) {
    homeViewModel.onNavigatedToShoppingSessions()
    navController.navigate(NAV_DESTINATION_SHOPPING_SESSIONS) {
        popUpTo(NAV_DESTINATION_AUTO_LOGIN) { inclusive = true }
    }
}
n
popUpTo("login") { inclusive = true // This removes login from back stack this will remove your backstack or login
l
That's what I already do
Yes
But then the shopping sessions is opened multiple times
n
okay "NAV_DESTINATION_AUTO_LOGIN" type manualy
don't use const variable
l
It doesn't matter 🙂
n
try
l
You can use variables, they don't change the code behavior 🙂
n
also use this code you are missing launchSingleTop = true
l
I already used it, it didn't help
Still the screen opened multiple times
n
navController.graph.startDestinationId use this code in popUpTo()
use LaunchedEffect
you didn't using launchedEffect
l
It also doesn't help
Copy code
LaunchedEffect(navigateToShoppingSessions) {
                if (navigateToShoppingSessions && navController.currentDestination?.route != NAV_DESTINATION_SHOPPING_SESSIONS) {
                    homeViewModel.onNavigatedToShoppingSessions()
                    navController.navigate(NAV_DESTINATION_SHOPPING_SESSIONS) {
                        popUpTo(navController.graph.startDestinationId) { inclusive = true }
                        launchSingleTop = true
                    }
                }
            }
Still opens the shopping sessions screen multiple times
n
val hasNavigated = remember { mutableStateOf(false) } LaunchedEffect(navigateToShoppingSessions) { if (navigateToShoppingSessions && !hasNavigated.value) { hasNavigated.value = true homeViewModel.onNavigatedToShoppingSessions() navController.navigate(NAV_DESTINATION_SHOPPING_SESSIONS) { popUpTo(navController.graph.startDestinationId) { inclusive = true } launchSingleTop = true } } } use above code
have you try ? if fix let me know
l
It doesn't change anything
Thank you for your help
I will figure it out by myself
n
could you show me login candition ?
l
Thank you for your help!
n
okay if you want help reach out to me
l
So the problem was that the
HomeActivity
was missing the
launchMode:singleTop
in manifest