Here is my code
<fragment
android:id="#+id/fragment1"
android:name="com.example.app.Fragment1"
android:label="SignatureFragment"
tools:layout="#layout/layout_fragment1">
<action
android:id="#+id/action_fragment1_to_main_activity"
app:destination="#id/main_activity"
app:enterAnim="#anim/slide_in_from_right"
app:exitAnim="#anim/no_anim"
app:launchSingleTop="true"
app:popEnterAnim="#anim/no_anim"
app:popExitAnim="#anim/slide_out_to_right"
app:popUpTo="#id/navigation_graph_id"
app:popUpToInclusive="true" />
</fragment>
<activity
android:id="#+id/main_activity"
android:name="com.example.app.MainActivity"
android:label="MainActivity"
tools:layout="#layout/activity_main" />
Now the code for navigation
findNavController().navigate(R.id.action_fragment1_to_main_activity)
When I navigate to activity and press back, the fragment is still there. I want to clear the backstack after opening the activity.
I tried to remove the animation and also tried with removing app:launchSingleTop, but no success.
Edit
Jetpack Navigation is intended to work with single activity and does not fully support activity navigation with parameters passed to actions
Thus to clear stack when navigating from one activity to another you will still need to call activity.finish()
Edit end
The thing is findNavController().navigate(R.id.action_fragment1_to_main_activity) wont work.
Try to navigate via navigate(#NonNull NavDirections directions). In your case it will look something like this
findNavController().navigate(
Fragment1Directions.actionFragment1ToMainActivity())
Hope it helps.
Related
I have a question. I'm using nav component for navigation. For example i have fragment A, B and C and bottomNavigation. I'm using
binding.bottomNavigation.setupWithNavController(navController)
For multiple backstack. But here is situation: Main frag is A. I'm moving to fragment B or C. I have buttons on fragments B and C which should lead me to fragment A with putted arguments in it so i'm using just:
findNavController().navigate(fragmentBDirections.fromFragmentBToFragmentA(argument))
But here is a problem. I'm recreating fragment A after this but i'm already have this fragment in backstack. So is it possible to find A in backstack and navigate to it without recreating? Is it possible to save backstack after that?
Your problem seems like an ideal case to use a sharedViewModel
Your button in B or C should pop and fallback to A after updating a property in the viewModel. On leaving, the viewModel is not destroyed because it is bound to the activity and is available for Fragment A.
Bonus is using LiveData so that the change is observed and updated automatically
I think SavedStateHandle might be helpful.
<Navigation>
<fragment
android:id="#+id/BFragment"
android:name="com.packageName.app.BFragment"
android:label="fragment_b"
tools:layout="#layout/fragment_b" >
<action
android:id="#+id/action_BFragment_pop_including_AFragment"
app:popUpTo="#id/AFragment"
app:launchSingleTop="true" />
</Navigation>
<Navigation>
<fragment
android:id="#+id/CFragment"
android:name="com.packageName.app.CFragment"
android:label="fragment_c"
tools:layout="#layout/fragment_c" >
<action
android:id="#+id/action_CFragment_pop_including_AFragment"
app:popUpTo="#id/AFragment"
app:launchSingleTop="true" />
</Navigation>
try it . it's my solution
I working on a social media App. when user click on a post, a new fragment open and some related post showing under it. if user click on a related post, new instance of that fragment must open and show clicked post and related posts under it. this page also have this behavior. each page must add to back stack.
for using navigation component, in this case destination fragment is current fragment with different argument.
can do this in navigation component?
we can open multiple instace of a fragment by using deeplink
in navigation.xm :
<fragment
android:id="#+id/navigation_profile"
tools:layout="#layout/fragment_profile_owner"
android:label="#string/profile" >
<deepLink
android:id="#+id/profileDeepLink"
app:uri="myapp://?user_id={user_id}" />
</fragment>
and then you can open new fragment by:
findNavController().navigate(Uri.parse("myapp://?user_id=${id}"))
and you can get arguemnt in destination fragment by:
arguments?.getString("user_id")
and put this in activity tag in manifest (if you want to open this page out of app):
<activity
android:name=".ui.activity.MainActivity"
android:label="#string/app_name"
android:screenOrientation="portrait">
<nav-graph android:value="#navigation/navigation" />
</activity>
I open some main fragment FragA, which then can open other fragments, that are added to the stack, but when I press back I show a DialogC, which should clear the stack and get me back to FragA, without loosing it's state, restore it from stack, rather then creating it - to recreate it I'll have to pass some arg through the whole stack.
I tried some configs with popUpTo in different places, and also used findNacController.popUpTo(with/out_aruments) or findNavController.navigate(R.id.action_dialog_c_to_frag_a) without destination defined in action, but pop can't find action in stack, navigate wants to recrete fragment when destination is defined, withou it cannot find pop action in stack (I/NavController: Ignoring popBackStack to destination frag_a as it was not found on the current back stack)
This is sample of my nav_graph:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<fragment
android:id="#+id/asdf"
android:name="SomeNaviFragment">
<action
android:id="#+id/action_asdf_to_frag_a"
app:destination="#id/frag_A" />
</fragment>
<fragment
android:id="#+id/frag_A"
android:name="FragA">
<argument
android:name="some_id"
app:argType="integer" />
<action
android:id="#+id/action_frag_a_to_frag_b"
app:destination="#id/frag_B" />
</fragment>
<fragment
android:id="#+id/frag_B"
android:name="FragB">
<action
android:id="#+id/action_frag_b_to_dialog_frag_c"
app:destination="#id/DialogFragC"/>
</fragment>
<dialog
android:id="#+id/DialogFragC"
android:name="DialogC">
<action
android:id="#+id/action_dialog_c_to_frag_a"
app:popUpTo="#id/frag_a"
app:popUpToInclusive="true"/>
</dialog>
</navigation>
In short - I wan't to go deeper from FragA through some fragments, but when the DialogC shows up in some point, I want to get back to FragA, to it's initial state. Is it possible to achive it without passing the creation arguments for FragA?
Some solution already tried, like: Navigate Back with Navigation Component with it's linked resources, but this didn't help at all.
I've used the article in your post to make this https://github.com/yoobi/backNavigation I hope it helps.
EDIT: you're looking for a combination of this and the article then.
The popUpTo attribute of an action "pops up" the back stack to a given destination before navigating. (Destinations are removed from the back stack.)
If the popUpToInclusive attribute is false or is not set, popUpTo removes destinations up to the specified destination, but leaves the specified destination in the back stack.
If popUpToInclusive is set to true, the popUpTo attribute removes all destinations up to and including the given destination from the back stack.
If popUpToInclusive is true and popUpTo is set to the app's starting location, the action removes all app destinations from the back stack. The Back button takes the user all the way out of the app.
You can also check the count of your backstack with : parentFragmentManager.backStackEntryCount
so I have the following navigation graph:
Fragment A (start) --> Fragment B
So for some situations (firebase notifications), I need to start Fragment B directly, passing data from the notifications. Now, this works. However, when I press the back button, it results in a crash. Is it because the leading fragment (Fragment A) is not in the stack? If so, is there a way to properly handle this.
Basically, I need the backPressed action to launch the start Fragment (Fragment A) in a situation where Fragment B is launched directly without passing through Fragment A.
Below is a snippet of my graph:
<fragment
android:id="#+id/homeFragment"
android:name="dita.dev.myportal.ui.home.HomeFragment"
android:label="Home"
tools:layout="#layout/fragment_home">
<action
android:id="#+id/action_homeFragment_to_messageDetailFragment"
app:destination="#id/messageDetailFragment"
app:exitAnim="#anim/fade_out_animation" />
</fragment>
<fragment
android:id="#+id/messageDetailFragment"
android:name="dita.dev.myportal.ui.messages.details.MessageDetailFragment"
android:label="Message"
tools:layout="#layout/fragment_message_detail">
<argument
android:name="title"
app:argType="string" />
<argument
android:name="message"
app:argType="string" />
</fragment>
I hope the link helps.
https://developer.android.com/guide/navigation/navigation-deep-link
Deep links allow for synthetic back-stacks.
Quoted from the website, "This means that when a user presses the Back button from a deep link destination, they navigate back up the navigation stack just as though they entered your app from its entry point."
Maybe trying to create a deep link for Fragment B will work.
My flow of fragment is like this
Main -> A -> B -> C ->A
In fragment c, it has a submit button which will return to A.
When I press back button in A, I want it back to Main. But it return to fragment c instead.
In fragment C, I use this
findNavController().navigate(R.id.action_c_to_a)
nav_graph.xml
<fragment
android:id="#+id/fragmentC"
android:name="xxx"
android:label="xxx">
<action
app:launchSingleTop="true"
app:popUpTo="#+id/fragmentA"
app:popUpToInclusive="true"
android:id="#+id/action_c_to_a"
app:destination="#id/fragmentA" />
</fragment>
Why not pop up to fragment A? You could just call findNavController().popBackStack(R.id.fragmentA, false) instead of navigating with an action.
try to look at my complete solution with removing/killing fragment from backstack.
Navigation Component set transition animation programmatically
You can override the back button behavior to do this.
Provide custom back navigation
The idea is to set a app:popUpTo without setting app:destination. Indeed, setting a app:destination will create a fragment and add it to the backstack which is not what you want.
To you can just remove :
app:destination="#id/fragmentA"
If you have this :
app:popUpTo="#+id/fragmentA"
And it will really pop the backstack until fragmentA