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 screen
→ Email 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?
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.
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.
<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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With