Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Navigation popUpTo and PopUpToInclusive aren't clearing the backstack

I'm new to the Android Jetpack Navigation architecture. I'm trying it out on a new app. There's one activity and a few fragments, two of them are login screen and email login screen. I defined those fragments in my navigations XML. The flow of the app is as follows:

Login screenEmail Login screen

What I want is, after navigating to the email login screen, when I press back, the app exits. Meaning the back-stack for login screen is removed. I know login screens aren't supposed to work that way, but I'm still just figuring things out.

I followed the documentation from Google's Get started with the Navigation component. It said, using app:popUpTo and app:popUpToInclusive="true" is supposed to clear the backstack, yet when I press back on email login screen, it still goes back to login instead of exiting.

So, here's what I've tried.

nav_main.xml

<fragment android:id="@+id/loginFragment"           android:name="com.example.myapp.ui.main.LoginFragment"           android:label="@string/login"           tools:layout="@layout/fragment_login" >          <action         android:id="@+id/action_login_to_emailLoginFragment"         app:destination="@id/emailLoginFragment"         app:popEnterAnim="@anim/slide_in_right"         app:popExitAnim="@anim/slide_out_right"         app:popUpTo="@+id/emailLoginFragment"         app:popUpToInclusive="true"/>  </fragment>  <fragment android:id="@+id/emailLoginFragment"           android:name="com.example.myapp.ui.main.EmailLoginFragment"           android:label="EmailLoginFragment"           tools:layout="@layout/fragment_login_email" /> 

LoginFragment.kt

override fun onCreateView(     inflater: LayoutInflater, container: ViewGroup?,     savedInstanceState: Bundle? ): View {     binding.emailLoginButton.setOnClickListener {         findNavController().navigate(R.id.action_login_to_emailLoginFragment)     }          return binding.root } 

I gave a click event to a button. In it, I used the Navigation Controller to navigate to the email login screen by giving it the action's ID. In the <action>, there are app:popUpTo and app:popUpToInclusive="true".

After reading the documentation over and over, as well as reading plenty of StackOverflow questions, I found those properties are supposed to remove my login screen off the back-stack. But they don't. The button does navigate to the email login screen, but when I press back, it still goes back to login screen instead of exiting the app. What am I missing?

like image 855
adrilz Avatar asked May 01 '19 07:05

adrilz


People also ask

What is App popUpTo?

app:popUpTo tells the Navigation library to pop some destinations off of the back stack as part of the call to navigate() . The attribute value is the ID of the most recent destination that should remain on the stack.

What is NavController in Android?

NavController manages app navigation within a NavHost . Apps will generally obtain a controller directly from a host, or by using one of the utility methods on the Navigation class rather than create a controller directly. Navigation flows and destinations are determined by the navigation graph owned by the controller.


2 Answers

<action         android:id="@+id/action_login_to_emailLoginFragment"         app:destination="@id/emailLoginFragment"         app:popEnterAnim="@anim/slide_in_right"         app:popExitAnim="@anim/slide_out_right"         app:popUpTo="@+id/loginFragment"         app:popUpToInclusive="true"/> 

Your popUpTo is going back to the email login, and then popping it because of the inclusive. If you will change the popUpTo to your login fragment, it will be navigated back to, and popped as well because of the inclusive flag, which will result in your desired behaviour.

like image 145
Rito Avatar answered Sep 19 '22 10:09

Rito


These 2 lines make the trick works:

If you want to go from A to B and expect to finish A:

You need to call B with this action:

    <fragment         android:id="@+id/fragmentA"                     tools:layout="@layout/fragment_a">          <action             android:id="@+id/action_call_B"             app:destination="@+id/fragmentB"             app:popUpTo="@id/fragmentA"             app:popUpToInclusive="true" />      </fragment>      <fragment         android:id="@+id/fragmentB"         tools:layout="@layout/fragment_b">       </fragment> 

If you put log to your fragments you can see that fragmentA is destroyed after calling fragmentB with this action.

like image 31
Cenk Avatar answered Sep 18 '22 10:09

Cenk