Navigation Component: Navigate from Fragment in Viewpager to another Fragment - android

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).

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.

how to detect if a fragment comes from previous fragment or comes from the fragment afterwards using navigation controller component in Android?

I am using navigation controller component. let say I have 4 fragments
A --> B --> C or D
from fragment A, it can only go to fragment B. but if we are in fragment B, it can go to fragment C or to fragment D.
I want to perform method workXYZ() in onResume fragment B if it comes from fragment A, and I want to perform method doSomethingABC() in onResume fragment B if it comes from fragment C or fragment D.
from fragment A to fragment B I use the code below:
val BDestination = FragmentADirections.actionToFragmentB()
Navigation.findNavController(fragmentView).navigate(BDestination)
to reach fragment C and fragment D from fragment B, I use global action. because fragment C & D are actually not only used by fragment B. so I use the code like below to go to fragment C or D
val CDestination = BFragmentDirections.actionGlobalFragment()
Navigation.findNavController(fragmentView).navigate(CDestination)
and from fragment C or fragment D, I use back button to be back to fragment B.
I have tried to use safe arguments boolean comesFromFragmentA = true in navigation graph in order to give a sign that fragment B comes after fragment A. but unfortunately, that value on safe arguments boolean comesFromFragmentA will remain the same (true) if it comes from fragment C or D.
so what should I do if want to know if the fragment B appears after previous fragment or from the fragment afterward ?
Fragment arguments are mutable so you can change them at any time. Therefore you can update that argument value right before you navigate to signify that future onResume() calls will be after you return to this Fragment:
// Set the comesFromFragmentA argument to signify that the next onResume()
// will be when you come back to this Fragment
arguments.putBoolean("comesFromFragmentA", false)
// Now navigate
val CDestination = BFragmentDirections.actionGlobalFragment()
Navigation.findNavController(fragmentView).navigate(CDestination)

How to get previous Fragment in Navigation

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.

startActivityForResult() alternative for fragment( getting task done by fragment and passing result to fragment)

>>activity B | activity B >> activity A
activity A >> |
>>activity C | activity C >> activity A
Activity A showing a viewpager which is scrolling through an arraylist of applicants
In Activity A we can click on a button and go to activity B or C activity B and C are doing task such as shortlisting or scheduling interview of an applicant after that it will come to activity A with some data in intent.
So B and C are called through startActivityForResult method, and returning the result along with an intent after doing the task.
My question is,
i am converting these activities to fragments(because i need to implement bottom navigation bar so wrapping these flow under a single menu) the first part, creating viewpager, going to each fragments are done now,
so it is now
Fragment A(viewpager), Fragment B(shortlist), Fragment C(schedule interview)
but if i have to return from the shortlist or schedule-interview fragment with the "result bundle" what should i do? simply ".replace()" the fragment with the viewpager fragment along with bundle without adding to backstack? i have cancel buttons in B and C(shortlist and scheduleinterview fragments) and i am implementing this cancel button with ".remove()" for fragment now, am i doing it correctly? or is there any workaround for this? and can we send a bundle to the calling fragment before the ".remove()" is happening? (can we remove shortlist or scheduleinterview fragment and send the data to the calling fragment ?)
I need to do this with fragments because I need to implement this within a bottom navigation bar

Fragment back stack clearing Issue

I am working with fragments and the navigation flow like
Fragment A -> Fragment B -> Fragment C -> Fragment D
Form fragment D I need to navigate to fragment A by clearing back stack but the problem is in onCreateView() method of fragment C I am showing one dialog
When I am navigating from D to A by clearing the back stack Over fragment A same pop-up appears which was shown in on fragment C
below is the code I am using to clear the stack
FragmentManager fm = getActivity().getSupportFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}
The problem you have lies in the way you are dealing with the fragments lifecycle. You want Fragment C to do onCreateView only once (to show the popup), but onCreateView get's called every time the View is created (e.g, every time you call remove on a fragment(replace works pretty much the same, remove + add) and then add it back from backstack with popbackstack).
For your problems there are two solutions:
Cleaner one: instead of showing your popup from onCreateView, call it from onCreate in Fragment C. With this you will guarantee that it only get's called when the fragment instance is created.
Not so clean: Instead of using replace between Fragment C and D transaction, call add, this way when you pop the backstack in Fragment D, Fragment C onCreateView won't be called because the View was never destroyed (never called remove/replace upon).

Categories

Resources