55

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?

Mahdi-Malv
  • 16,677
  • 10
  • 70
  • 117

9 Answers9

68

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

iknow
  • 8,358
  • 12
  • 41
  • 68
58

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)
}
Mahdi-Malv
  • 16,677
  • 10
  • 70
  • 117
16

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.

bboyairwreck
  • 331
  • 3
  • 6
9

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

Ban Markovic
  • 690
  • 1
  • 7
  • 12
  • 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. – Mihail Ya Jul 05 '23 at 08:37
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)
}
Abdul Mateen
  • 1,139
  • 1
  • 14
  • 21
3

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)
}
Jaydipsinh Zala
  • 16,558
  • 7
  • 41
  • 45
2

Jetpack Compose v1.0.5

navController.backQueue.removeIf { it.destination.route == "Splash" }
navController.popBackStack()
Hun
  • 3,652
  • 35
  • 72
1

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)
  }
Boobalan
  • 815
  • 11
  • 11
0

this solved the issue for me

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

it removes the last one though

Sourav
  • 312
  • 1
  • 8