# Building an artificial back stack with the Android Navigation component

## Context

Backwards navigation with Navigation Component isn't a mystery, is it? We don't have to do anything, we have it for free.

But, what if you want to navigate straight to a specific destination? And be able to navigate back to the *start destination*? Like if you had navigated manually to that specific destination.

I expected that the backwards navigation continues working but it doesn't. And this is the reason that this article exists.


> **Note**: [deep linking](https://developer.android.com/guide/navigation/navigation-principles#deep-link) provides this behaviour. It simulates manual navigation and creates a synthetic back stack.


## Understanding the  back stack

The first thing is to understand what the back stack is and how it works with the Navigation component. The back stack is a [LIFO stack](https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29) that stores the activity and its fragments. The last fragment pushed onto the back stack will be the first fragment popped off the stack when we hit the back button.

For example, if we have the following navigation:

**Fragment A -> Fragment B -> Fragment C**

Its back stack will look like this:

![Navigation Component.drawio.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640264125412/OzRTVq0uK.png)

If we hit the back button, the fragment on the top is popped off the stack and now **Fragment B** is in the foreground:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640432303538/O49pu5i5l.png)

Hit the back button again and **Fragment B** is popped off the stack:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640432342329/FBhdGv6jOj.png)

Finally, if we hit the back button one more time, **Fragment A** and the activity are popped off the stack and we exit the app:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640432504434/6wHzc4WU9.png)

This backwards navigation behaviour comes for free, we don't have to do anything.

## Problem
The described behaviour works as long as we navigate manually to a destination. Yet, what if we want to navigate to a specific destination skipping destinations in between? And be able to navigate back to the *start destination*?

You can think of a sign-up flow for example. You may want to let the user leave the flow at any point. And allow him to rejoin the flow at the last point he left (and don't lose a user because of a long sign-up process).

In this case, the backwards navigation isn't what we expect. If we navigate straight to **Fragment C** and hit the back button, we won't see **Fragment B**. We'll see **Fragment A**. What is happening is that **Fragment B** wasn't pushed onto the back stack because we never navigated to it.

![Navigation Component.drawio (5).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640343721839/Bpidq-6pA.png)

## Solution
To amend this problem, the solution I've found is that we have to build the back navigation ourselves.

## Show me the code
You can find the code [here](https://github.com/ErikMedina/NavigationComponent/tree/artificial-back-stack) (`artificial-back-stack` branch).

The aim is to have a navigation graph where all the destinations are connected forwards and backwards:

![NavGraph](https://cdn.hashnode.com/res/hashnode/image/upload/v1640346305799/WzQorMEOk.png)

For this example, I'll have `HomeFragment` as the *start destination*; and `FirstFragment`, `SecondFragment` and, `ThirdFragment` as destinations.

%[https://gist.github.com/ErikMedina/d530c66fd981dc29c969e606d677531e]

The graph will look like this:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640284988306/l36128Lip.png)

Once we have the forwards navigation, we have to build the backwards navigation. Thus, when we navigate straight to a destination, we're still able to navigate back to the *start destination*. For that, we have to add the actions for the backwards navigation:

%[https://gist.github.com/ErikMedina/72f97472659641903bf8d4aa56d3dddf]

We also have to provide  [custom back navigation](https://developer.android.com/guide/navigation/navigation-custom-back) to our fragments and specify the action. For example, this is how we'd provide custom back navigation to `FirstFragment`:

%[https://gist.github.com/ErikMedina/d6623364f2fca109ce86bc4f1ed45da5]

Everything seems to work fine. We can navigate through the navigation graph forwards and backwards. However, when we navigate back to the `HomeFragment`, we'll notice a bug. We enter a loop between the `HomeFragment` and the `FirstFragment` and can't exit the app:

%[https://youtu.be/rBA6xQQvuZQ]

### What is happening?
Let's analyse the back stack to understand what is happening. The back stack when we launch the app:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640353497452/ktHLFSNKW.png)

We navigate to the `FirstFragment` and then to the `SecondFragment`:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640380155584/QWN4dqbHs.png)

When we hit the back button, because of the `action_secondFragment_to_firstFragment` action, a new destination (`FirstFragment`) is **added**:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640380273885/xdQx2wMLd.png)

Hit the back button again and, because of the `action_firstFragment_to_homeFragment` action, a new `HomeFragment` is added:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640380497938/MIZ20ia7O.png)

Back button again and the `HomeFragment` is popped off the stack (`FirstFragment` is visible again). Hit back again and a new `HomeFragment` is added, and so on:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640437537176/StJwYDmOn.png)

### How to fix the loop bug
We have to specify the `app:popUpTo` attribute in the `action_firstFragment_to_homeFragment` action. By including `app:popUpTo="@id/homeFragment"`, we're telling the navigation graph that all the destinations are popped off the stack until reaching the specified destination (`HomeFragment`). With this attribute, we've fixed the loop bug.

%[https://gist.github.com/ErikMedina/f8b0a5d1d4b09e997907c80733f34c7d]

However, there is a new bug. We need to hit the back button twice when we're in the `HomeFragment` to exit the app:

%[https://youtu.be/L7B98xyQIxU]

Let's analyse the back stack again to understand why this new bug is
happening. The back stack when we navigate to the `FirstFragment` and then to the `SecondFragment`:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640381587035/DQiLSk-nh.png)

Let's start hitting the back button, a new `FirstFragment` is pushed onto the back stack:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640381756129/5Z5RYo4PX.png)

Because of `app:popUpTo="@id/homeFragment"`, when we hit the back button again, all the fragments are popped off the stack until reaching the destination `HomeFragment`. And a new `HomeFragment` is pushed onto the back stack:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640382186745/fSBsCjOFt.png)

Now we have two `HomeFragment` instances and this is the reason why we need to hit the back button twice to exit the app.

### How to fix this new bug
The `app:popUpToInclusive` attribute fixes the bug:

%[https://gist.github.com/ErikMedina/c4c8a55996faa5fa4d0976c4ad9c9f2c]

This attribute pops the target off the stack as well:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1640382841297/LP9lf7yuo.png)

Now we only have one `HomeFragment` in the back stack and hitting the back button once will exit the app:

%[https://youtu.be/94z1Eihb7Mg]
 
You can learn more about `app:popUpTo` and `app:popUpToInclusive` [here](https://developer.android.com/codelabs/basic-android-kotlin-training-navigation-backstack#3) (skip to the *Pop additional destinations off the back stack* section).

## That's all
I don't know if there is a better way of achieving this. I couldn't find anything that solves this problem. After investigation, this is the solution I came up with.




