16

so I'm using the android navigation component and I have a problem (2.2.0-rc04 version).

I have a welcomeFragment(wF). From wF I want to navigate to loginSellerFragment(lSF) which is in a different navigation graph. I also don't want to remove wF from backstack ( popUpTo, popUpToInclusive) when navigating to lSF because a user might wanna go back to it.

<fragment android:id="@+id/welcomeFragment"> <action android:id="@+id/action_welcomeFragment_to_nav_onboarding_seller" app:launchSingleTop="true" app:destination="@id/nav_onboarding_seller" /> </fragment> 

After navigating to lSF the backstack looks like this : wF lSF

We're on lSF now, after login we want to go to feedFragment(fF) which again is in a separate graph, but this time we want to clear all the backstack, because if a user is logged in and presses back he wants the app to exit, not to take him back to wF or lSF, so I used popUpTo="@id/loginSellerFragment popUpToInclusive='true" in the action from lSF to fF.

<fragment android:id="@+id/loginSellerFragment"> <action android:id="@+id/action_login_to_seller" app:destination="@+id/seller" . //this is the graph that has as firstDestination, feedFragment app:launchSingleTop="true" app:popUpTo="@id/loginSellerFragment" app:popUpToInclusive="true" /> </fragment> 

So in the backstack in this moment should be only fF because we removed everything up to lSF(lSF included)

The problem

When I'm on fF and press back, the app doesn't close, instead it takes me to wF ( wF should have been popped off the backstack already)

What I've tried

I've tried instead of popUpTo="@id/loginSellerFragment popUpToInclusive='true" to use popUpTo="@id/welcomeFragment popUpToInclusive='true" and it worked fine, but I'm pretty sure that this is not how it should be done. What am I missing here guys? Am I building the backstack wrong?

Also I've tried adding popUpTo="@id/welcomeFragment popUpToInclusive='true" after navigating from wF to lSF , but this will break my user experience, because I don't want the app to exit when I'm still in the login process.

Please note that all of this fragments are in separate graphs. To navigate I use FragmentDirections e.g : findNavController.navigate(WelcomeFramgentDirections.actionXtoY())

2 Answers 2

28

It's not easy to grasp how Navigation Component manipulates backstack when you are using popUpTo option.

The solution you mentioned in your question is correct: You indeed should use popUpTo="@id/welcomeFragment" popUpToInclusive="true" instead of popUpTo="@id/loginSellerFragment" popUpToInclusive="true".

I will try to explain why.

  • When you launch your application, your backstack will be empty and welcomeFragment will be displayed.

  • When you navigate from welcomeFragment to loginSellerFragment, you will have welcomeFragment in your backstack.

  • Than if you login, you will navigate from loginSellerFragment to feedFragment, and in backstack you will have loginSellerFragment and welcomeFragment.

Since you used popUpTo="@id/welcomeFragment", aplication will start to pop (remove) fragments from your backstack until it reaches welcomeFragment. The welcomeFragment will be also removed since we used popUpToInclusive="true".

Backstack should behave like FILO (First In Last Out) stack, so it will remove fragments in this manner:

First the top fragment will be removed and that is loginSellerFragment.

Next, welcomeFragment will be the top fragment. Since we need to pop up fragments until we reach welcomeFragment this is where we stop, but welcomeFragment will be also removed because of popUpToInclusive="true" and your backstack will be empty.

If you try to navigate back from welcomeFragment, you will exit app because your backstack is empty.

I hope that this helps. You could also read more about stack data structure.

Sign up to request clarification or add additional context in comments.

4 Comments

Actually I started to debug a little bit the nav component and came to the conclusion that "I was wrong saying that I'm wrong" :)). Indeed, Initially I tought that popUpTo it will start poping up elements from the root of the graph until it reaches the fragment, but it actually behaves in the opposite way( it starts with the most recent fragment added until it reaches the specified fragment. I still find this counter intuitive, but it's nice that somebody finally explained it.
I do have a question tho, I logged the onCreate and onDestroy and it seems that first it destroys loginSellerFragment and then welcomeFragment. Here are the logs : 14:56:55.898 WelcomeFragment is destroyed 14:56:55.907 SellerLoginFragment is destroyed . What's the reason for this?
If you follow second half of my answer, thats the order in which they are supposed to be destroyed. First, the loginSellerFragment and than the welcomeFragment. One thing not to be confused about: pop up of fragments is not related to graph, but to a backstack.
I find this unintuitive as well. I get that they want to use "up to" but then it's a stack, so really "up" is toward the recent, but at the same time, android operates on "up=previous", so there's the contradiction(if i'm not mistaken) and confusion.
12

For me setting XML code didn't really solve the issue, had to use an extra line of code

 findNavController() .navigate(R.id.navigationFragment, null, NavOptions.Builder() .setPopUpTo(R.id.splashFragment, true).build() ) 

2 Comments

It is same for me. I had the same problem and your solution saved me. Thanks a lot.
same for me, xml did not pop up my specified fragment, but in code it worked

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.