How to get previous Fragment in Navigation - android

I use AndroidX Navigation to navigate Fragment in my app。
From A to B, and i want to get A in B, but i find there is no way to get A.
I try to get the backstack from FragmentManager, but the BackStackRecord's id is not useful.

Related

Android NavigationComponent - Remove fragment after changing activity

I'm facing an issue concerning the use of navigation component.
I have this hierarchy :
Activity A composed of fragment f1 and fragment f2
Activity B
When I'm on f2, I change activity like this :
button.setOnClickListener {
startActivity(Intent(activityA, ActivityB::class.java))
}
What I would like is : When I go to activity B, the fragment f2 (of activity A) should be removed. So, when I will kill the activity B, I will come back to activity A without fragment f2.
To illustrate the flow :
Activity A (f1 > f2) > Activity B (Need to remove f2)
When I will come back : Activity B > Activity A (f1 only)
I'm using navigation component and I have tried to use the popUpTo and popUpToInclusive options in my nav_graph. I managed to remove the fragment but there is always a glitch when I remove it (i.e. we see the removal of fragment before passing the activity B, so we see the f1 fragment a little time). I would like to make the transaction invisible to user.
Is there a way to do it ? Don't hesistate to ask me if you need more precisions.
Thanks for your answers,
When you're using the navigation component, you can have direction, then use the navigation component to move from origin fragment/activity to destination fragment/activity. For example:
val actionLockToLogin = LockFragmentDirections.actionLockToLogin()
NavHost.findNavController(this).navigate(actionLockToLogin)
In this code, I go from LockFragment, to LoginFragment. Just add the fragments or activities in the navigation's XML. Set an Action from origin fragment / activity to destination fragment / activity. and by using the code I show you, try to navigate between them.

Navigation Component: Navigate from Fragment in Viewpager to another Fragment

I have a Fragment A which navigates to Fragment B
Fragment B hosts a ViewPager2.
ViewPager2 has two fragments inflated in it - Fragment C and Fragment D.
On clicking an item in Fragment C I want to navigate to a new instance of Fragment D on top of Fragment B.
Currently, my code is something like this -
findNavController().navigate(
R.id.action_FragmentC_to_FragmentD,
bundleOf("id" to id, "type" to "list")
)
However, when I try to navigate I get the following exception -
java.lang.IllegalArgumentException: Navigation action/destination com.test.at:id/action_FragmentC_to_FragmentD cannot be found from the current destination Destination(com.krtkush.audiotime:id/FragmentB) label=FragmentB
From what I can understand is that the navigation component is still on Fragment B but I'm trying to navigate to Fragment D from Fragment C and hence it is throwing an exception.
I (think) can fix this by adding a listener which informs Fragment B when the item is tapped in Fragment C and then navigate to Fragment D from Fragment B. However, this will make my Fragment C tightly coupled to Fragment B which I don't want to. Anyway to fix this is another way?
If you do not navigate() to Fragment C and Fragment D, you will remain on the last destination you navigated to: Fragment B, that is the expected behavior. The NavController knows nothing about child fragments such as fragments within a ViewPager of Fragment B and therefore you were never on Fragment C as a destination.
If you never navigate() to Fragment C and it is only viewable as part of your ViewPager, then Fragment C should not be in your graph. Any actions from fragments within Fragment B's ViewPager should be actions on Fragment B directly (the destination you're actually on).
Note that you can reuse the same actions names on fragments such as Fragment D if you are also using them as standalone destinations in your graph (thus ensuring that the action is available in both cases).

Get last fragment by tag

I add fragments to back stack. For instance: A, B, C, A, D. Then from D I want to update the second A.
If I use supportFragmentManager.findFragmentByTag("A"), I have a reference to the first A, that is in a bottom of the back stack.
I tried to search through fragments collection, getBackStackEntryAt(i), but with no success.
Sorry, looking at get the latest fragment in backstack I understood that findFragmentByTag(tag) finds the last fragment with required tag. In my case after adding many fragments it sometimes found not last fragment with tag, but a previous to last (with the same tag). Maybe there is a bug in my code, I don't know, why is that.
First I tried to use callbacks, then tried to use parentFragment and childFragmentManager, see getParentFragment returning null. In fragment D I called parentFragment and accessed to methods of A and could update the last A fragment. This solution has two problems.
1) Child fragment (D) inherits a toolbar from parent (A) and adds own buttons. And after clicking Back button we return not to a parent, but even quit parent (A).
2) If we want to update not previous fragment (so that between A and D are also 3 fragments), it seems to be impossible.
So, I cancelled that solution and changed the application behaviour. I clear a backstack where it is possible. So that we cannot have two A fragments in backstack. I use supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE). Yes, that's a workaround, but I don't know, how to deal with that bug.

How to know from what fragment I'm returning when using Navigation Component?

I have four fragments already set up in my app using Navigation Components:
I can go from MainFragment to MoviesFragment or TrailersFragment as well as from the UserFragment to one of them.
From the MainFragment I can simply navigate to the MoviesFragment fragment using this code:
ActionMainFragmentToMoviesFragment action = actionMainFragmentToMoviesFragment();
action.setFromMainFragment(true);
Navigation.findNavController(rootView).navigate(action);
To navigate to the TrailersFragment fragment, I'm using similar code. When I use:
.setFromMainFragment(true);
In MoviesFragment for instance, I can simply get a boolean from the Bundle so I can know from which fragment I'm coming from, either from MainFragmnet or UserFragment and it workd very well.
And here comes the problem. When I want to get from MoviesFragment back to MainFragment, I don't navigate as above, I just press the back button. So the problem is that I don't know in the MainFragment from which fragment I'm returning (MoviesFragment or TrailersFragment).
What should I do to know from which fragment I'm coming from in MainFragment?

Component Navigation , pop from backstack with arguments

Let's say I have three fragments, A, B, C;
A -> B <-> C
Between B and C it is a circular relationship. Either B or C fragments requires arguments, example
val args = Bundle()
args.putString("StringKeyBC", argValueBtoC)
findNavController().navigate(R.id.action_fragmentB_to_fragmentC, args, null)
args.putString("StringKeyCB", argValueCtoB)
findNavController().navigate(R.id.action_fragmentC_to_fragmentB, args, null)
The problem is that every time I move between B & C, the fragments are added to back stack and I don't want that. If the fragment is already to back stack I want just to pop it, but if I use popBackStack I can not add arguments anymore:
public boolean popBackStack(#IdRes int destinationId, boolean inclusive)
So, how can I constanlty switch between the two fragments without adding them every time to back stack?
You can pop fragments from back stack simply by adding a popUpTo attribute to a navigation action. This way you navigate using an action with arguments, but with pop back stack behaviour.
For example, you can add attribute app:popUpTo="#+id/fragmentB" to the action action_fragmentC_to_fragmentB. This way you'll be popping fragmentC from backstack each time you go from fragmentC to fragmentB.
See the docs with example for this here.
There's another option, which is likely an overhead for the case you described, but that allows to use popBackStack method and send arguments - using 'navigate back with result' approach. For it fragments should implement an interface (callback) with a method that receives bundle. Use addOnBackStackChangedListener in the fragment manager to trigger this method, providing all the data necessary, after popBackStack is called. (Described here in the section "How to navigate back with a result?": https://medium.com/google-developer-experts/using-navigation-architecture-component-in-a-large-banking-app-ac84936a42c2, and with slightly different implementation here: https://medium.com/#zawadz88/david-vávra-thank-you-for-this-great-article-ae3e602b880a)

Categories

Resources