Compose-Navigation: Remove previous composable from stack before navigating
R

10

75

I'm using compose-navigation(alpha09) to handle the navigation between composables

I want to remove the Splash screen when moving to the next destination (I don't want the back pressed to get back to Splash)

Following attempts did not work as expected:

navHostController.navigate(Route.login.id) {
    navHostController.graph.clear()
}
navHostController.navigate(Route.login.id)
navHostController.graph.clear()
val currentDest = navHostController.currentDestination
navHostController.navigate(Route.login.id)
if (currentDest != null) {
   navHostController.graph.remove(currentDest)
}

So how can I remove the Splash screen and then move to next?

Rawalpindi answered 28/3, 2021 at 20:28 Comment(0)
L
104

In Jetpack Compose 1.0.0 to navigate and remove the previous Composable from the back stack You can use:

navController.navigate(Screens.Login.name) {
    popUpTo(Screens.Splash.name) {
        inclusive = true
    }
}

The above code will navigate from the Splash screen to Login and will pop everything up, including the Splash screen.

Navigate to a composable - docs

Loram answered 8/7, 2021 at 14:55 Comment(2)
Cool. Thank. I'll accept yours since my old self-answer is obsolete now.Rawalpindi
Great it worked, popUpTo(0) have not worked for meRatter
R
82

For v1.0.0-alpha09 (And 1.0 stable)

Using popUpTo(0) you can clear the stack before navigating to the next destination. So:

navHostController.navigate(Route.login.id) {
    // popUpTo = 0 // DEPRECATED
    popUpTo(0)
}
Rawalpindi answered 28/3, 2021 at 20:28 Comment(9)
popUpto is deprecatedDisadvantage
@Disadvantage But not popUpTo(0)Acetone
Valid solution for 1.0.0 stableCardoza
The only one that worked for me, I'm surprised that this is not mentioned anywhere in the docsAlcock
I have never succeeded in popping the back-stack. This is the only way that worked for me, thanks!Cranial
why we have to give zero, what is the purpose of thatDefend
Works fine for latest versionCosmetic
The solution I found that is avoiding hard-coding 0, you can use first element from navHostController.backQueue and pass its id to popUpTo: popUpTo(navHostController.backQueue.first().destination.id) For more info, here is the detailed explanation medium.com/@banmarkovic/…Hetzel
Don't use this. As Ban Markovic said, this can only work by accident. You should pass destination id as argument instead.Schoolmarm
S
27

For a consistent reusable function that does not need to be aware of the current route, use this NavOptionsBuilder extension function

fun NavOptionsBuilder.popUpToTop(navController: NavController) {
    popUpTo(navController.currentBackStackEntry?.destination?.route ?: return) { 
        inclusive =  true
    }
}

^ Similar to other answers, it popUpTo the current route, but rather than needing to name the specific current route, it instead gets it from the backstack entry.

Now you can use it like so:

navController.navigate(ScreenRoutes.Login.route) { popUpToTop(navController) }

^ That example navigates to Login, and should clear the entire backstack before it.

Sacco answered 17/2, 2022 at 21:4 Comment(1)
clean and more dynamic way to achive this. great helpManaker
H
21

Apart from screens, back stack contains navigational graphs, and its root is always the first thing in back stack. Our NavHostController contains graph, so by popping its id, you are able to clear your back stack:

popUpTo(navHostController.graph.id)

For more info, here is the detailed explanation https://medium.com/@banmarkovic/jetpack-compose-clear-back-stack-popbackstack-inclusive-explained-14ee73a29df5

Hetzel answered 3/1, 2023 at 13:2 Comment(1)
That's the only correct answer. Pls, rate it up to make sure everybody will follow this approach. Other answers contain mistakes - the start destination can be removed from the back stack in the runtime. In this case findStartDestination returns a non-existing route that was already removed from the back stack. And that's why popUpTo(navController.graph.findStartDestination().id) won't pop up any route.Flyer
F
8

For clearing all back stack

To remove multiple composable screens from the stack use the below snippet

navController.navigate(ScreenRoutes.Login.route){
                    popUpTo(navController.graph.findStartDestination().id){
                        inclusive = true  }}

Or To keep Home in back stack

navController.navigate(ScreenRoutes.SelectCourseLayout.route){
    popUpTo(ScreenRoutes.Home.route)
}
Farewell answered 20/9, 2021 at 10:58 Comment(0)
G
7

To clear the back-stack, you can simply create this Extension function and reuse it wherever applicable.

fun NavHostController.navigateAndClean(route: String) {
    navigate(route = route) {
        popUpTo(graph.startDestinationId) { inclusive = true }
    }
    graph.setStartDestination(route)
}
Greaser answered 10/10, 2022 at 9:54 Comment(0)
C
2

Jetpack Compose v1.0.5

navController.backQueue.removeIf { it.destination.route == "Splash" }
navController.popBackStack()
Confabulation answered 4/1, 2022 at 2:4 Comment(1)
Cannot access 'backQueue': it is private in 'NavController'Teresita
S
1

this solved the issue for me

navigator.popBackStack()
navigator.navigate(myroute){
    launchSingleTop = true
}

it removes the last one though

Shenika answered 22/4, 2023 at 6:41 Comment(0)
S
0

After so many try, I've found the better way to clear the back stack during the logout scenario. Most of the production app will clear the splash or sign in screen as soon as we navigate to Home screen and there would be a multiple way to land into Home screen as well.

So, we may not know the initial screen to perform the popupTo. If there is a bottom bar, then story would be too difficult as well.

Here is a magic could that work all the scenario

 val firstBackStackRoute = navController.backQueue.firstOrNull()?.destination?.route
 firstBackStackRoute?.let { 
        navController.popBackStack(firstBackStackRoute, true)
  }
Sanjay answered 18/7, 2022 at 15:59 Comment(1)
Using the backQueue is not a good ideaTeresita
V
0
BackHandler {
    navController.popBackStack()
}

This one worked for me . This will pop the last stack value.

Viv answered 29/4 at 5:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.