Search code examples
android-jetpack-composeandroid-jetpack-navigation

How to clear backstack when browsing Jetpack Compose?


I'm implementing the Logout action in an application. I want that when user clicks Logout, go to Login. When the user takes this path: Login -> Home -> Settings (where he clicks on Logout) -> Login, when I press back, the app goes to the background and closes, which is the behavior I want.

However, when the user takes this route: Login -> Home -> ScreenOne -> ScreenTwo -> Home -> ScreenOne -> Settings (where you click on Logout) -> Login, when you press back, it goes back to Settings and if you press it again it goes to ScreenOne and so on .

That's the way I do the navigation to Login when I click on Logout:

navController.navigate(NavigationItem.Login.route) {
            popUpTo(NavigationItem.Login.route) {
                inclusive = true
            }
        }

Note: Already tried Navigation.Home.route as parameter on popUpTo.

I don't know if is related, but that's the way I do the navigation between Home -> ScreenOne -> ScreenTwo -> Home -> ScreenOne:

navController.navigate(item.route) {
                    navController.graph.startDestinationRoute?.let { route ->
                        popUpTo(route = route) {
                            saveState = true
                        }
                    }

                    launchSingleTop = true
                    restoreState = true
                }

Does anyone knows how I can clear the back stack or guarantee that, in the second behavior, when I am on Login screen after Logout and I press "Back", the app goes to second plan?

EDIT: Added NavHost structure.

@Composable
@ExperimentalFoundationApi
@ExperimentalComposeUiApi
@ExperimentalMaterialApi
fun Navigation(navController: NavHostController, updateBottomBarVisibility: (Boolean) -> Unit) {
    NavHost(
        navController = navController,
        startDestination = NavigationItem.Login.route
    ) {
        composable(route = NavigationItem.Login.route) {
            LoginScreen(navController)
        }

        composable(route = NavigationItem.Events.route) {
            EventsScreen(updateBottomBarVisibility, navController)
        }

        composable(route = NavigationItem.Home.route) {
            HomeScreen(updateBottomBarVisibility, navController)
        }

        composable(route = NavigationItem.Prizes.route) {
            PrizesScreen(updateBottomBarVisibility, navController)
        }

        composable(route = NavigationItem.Account.route) {
            AccountScreen(navController)
        }
    }
}

Solution

  • When you are in settings logout:

    navController.popBackStack(NavigationItem.Login.route, inclusive = false, saveState = false)
    

    is not necessary to save the state since once the use is out has to login again with new updated data.

    At this point if the user click back the app should go in foreground.

    If this doesn't work is possible that Login screen is not on the backstack. I would try to add a route to the NavHost and popBack to it with exclusion and save state off.

    Otherwise might be that you are invoking navigate method more times thank expected

    fun Navigation(navController: NavHostController, updateBottomBarVisibility: (Boolean) -> Unit) {
        NavHost(
            route = "nav_host_route"
            navController = navController,
            startDestination = NavigationItem.Login.route
        ) {}
    
    //navigate to top destinations like HOME
    navController.navigate(item.route) {
                        popUpTo(route = "nav_host_route") {
                            inclusive = false
                            saveState = true
                        }
                      
                        launchSingleTop = true
                        restoreState = true
                    }
    

    log out:

    navController.navigate(LogIn){ 
        popUpTo("nav_host_route"){
            saveState = false
            inclusive = false
        }
        restoreState = false
        launchSingleTop = true
    }