Jetpack Compose clear back stack, popUpTo/popBackStack inclusive explained

Ban Markovic
5 min readJan 3, 2023

--

Building the navigation for our Android app that is built with Jetpack Compose requires usage of navigation-compose library that is provided by Android team. In order to master closing the screens and tracking our back stack state, it is important to understand the stack data structure that is used for this purpose.

Before we can close multiple screens, we need to open them. That’s why I decided to separate this article into three sections that represent the most common ways used when navigating through apps:

  1. Opening a new screen,
  2. Closing current screen,
  3. Closing multiple screens at once.

Open new screen

Navigating from one to another screen is pretty straightforward using navigation-compose lib, we can just use NavHostController and call navigate(…) function with the route as parameter. This will lead into creating a new screen, that is going to be placed on top of our current screen.

Example

Let’s say we have our Login screen opened, and after successful email and password input, we want to load Home screen, our stack would look like this.

Close current screen

Apart from navigating to a new screen, closing the currently opened one is also a pretty common action in navigation. To achieve this, we can use popBackStack() function from our NavHostController. As the name of the function suggests, it will take the top screen from the stack, and it will remove it.

Example

Removing our Home screen by calling the popBackStack function will make our stack look like this.

Close multiple screens

The past two examples were pretty simple, but I wanted to make sure that we understand how navigation-compose lib is storing the data regarding the order of our opened screens.

When it comes to closing multiple screens, we can actually use an already known function, popBackStack, but we will need to pass two parameters:

  1. route — represents the destination (screen) that already exists in our stack, and it will enable popBackStack to close all screens that were opened after our destination screen,
  2. inclusive — a boolean that tells the popBackStack function if it should close the destination screen or not.

Example

Easiest way to understand this is to take a look into a use case where a user opens Profile screen from Home screen, and he presses Log out button. That action should close Profile and Home screens and the Login screen should be opened.

Using popBackStack with “login” as a route is a logical solution here, but we also have to set inclusive parameter, and we have two options:

  1. inclusive = false — our old Login screen will remain and it will be opened after closing Profile and Home.
  2. inclusive = true — our old Login screen will be closed together with Profile and Home; this will also require the user to manually open a new Login screen after closing all three.

It is important to say, in case you want to do popBackStack with a route that doesn’t exist in your back stack, no screen is going to be closed.

Clear back stack

As we saw, in order to close multiple screens, we need to define a destination route which will be used by a NavHostController to close all the screens that were opened after a given destination.

So what happens if we want to close all currently opened screens, but we don’t know which one was the first? Currently there is no built-in function, but I will show you how you can accomplish clearing of the back stack.

One important fact that we should not skip is that the back stack doesn’t contain only screens as destinations; it also contains navigational graphs.

When setting up the NavHost, apart from NavHostController and startDestination, you are able to pass a route parameter, which is basically the name that is going to be given to the NavGraph inside a NavHostController.

You may ask, why is this important, well it’s important because the root navigation graph is always going to be the first destination on the back stack. With that in mind, you can pass the route of your NavGraph to the popBackStack or popUpTo, and by doing that, you are going to clear that back stack. In case you didn’t set up the route parameter for NavHost, no worries, you are able to access the NavHostController’s graph and its id. Since popBackStack and popUpTo can also work with ids of our destinations, we can clear the back stack by passing the graph’s id from the NavHostController.

There you go, now you are able to clear your back stack!

Please bear in mind, that you should always prefer to use popUpTo over popBackStack, because with popBackStack you must never forget to call navigate function afterwards, otherwise you can end up in having empty back stack.

Final thoughts

Having the general idea of how the NavHostController handles navigation and how you can use it to manipulate your own back stack is something every Android developer should know. Hopefully you found this article helpful, if so please follow for more similar content, and if you prefer a bite-sized content about Android, you can consider following me on Twitter. In case you want to connect on a more professional level, here is my LinkedIn. Thanks for your time!

--

--

Ban Markovic

Android Engineer who writes about his learnings of KMM and Jetpack Compose