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.
Related
such as Fragment A -> Fragment B -> Fragment C -> Fragment D.
how can i restart Fragment A just like Activity singleTask launch mode.
The way I figure out that Fragment D invoke popBackStack 4 Time And add a New Fragment A to backstack. Using Fragment animation to make it look like back to FragmentA. But it's just a visiual cheating.
And someTime, I don't know how many times I have to popBackStack.
Is there any way to do that without using Jetpack Navigation?
Oh, I found the function can solve this question.
popBackStack(String name, flag)
I use it wrongly before which make it didn't work. (what a stupid mistake, I forget to set Framgent name in backstack)
We need to set the fragment name while add to fragment backstack.
After we set the name, popBackStack(name, flag) can work.
while flag = 0, the target Fragment will not be popped;
while flag = 1, the target Fragment will be popped too;
public void addFragmentToBackStack(Fragment fragment) {
getSupportFragmentManager().beginTransaction()
.addToBackStack(fragment.getClass().getName())
.replace(R.id.fl_container, fragment, fragment.getClass().getSimpleName())
.commitAllowingStateLoss();
}
I currently have this nav_graph.xml file.
Activity A (parent container), with this navigation tree:
Fragment A -> Fragment B -> Fragment C -> Fragment D -> Fragment E.
Also, I have an Activity B, and I want to navigate directly to Fragment C from this activity.
Does anyone know how I can realize an elegant solution for this case?
I have thought that I could launch an intent from Activity B -> Activity A passing it as an extra an enum corresponding to the desired fragment and that Activity A would handle the received parameter navigating through an action to the corresponding fragment. How do you see it? I think it can be improved and that's why I'm looking for a second solution. thanks!
Add this (your nav host fragment) in both of your activities with
<androidx.fragment.app.FragmentContainerView
android:id="#+id/nav_view_pager_host"
android:layout_width="match_parent"
android:layout_height="670dp"
app:layout_constraintBottom_toTopOf="#+id/bottomNav"
android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="#navigation/main_nav_graph"
app:defaultNavHost="true"/>
and then in your activity B onCreate() just add
val navController = (supportFragmentManager.findFragmentById(R.id.nav_view_pager_host) as NavHostFragment).navController
navController.navigate(/* To your fragment B*/)
//Handle anything else you wanna ddo
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).
I've a fragment A. I add() it with tag like this:
fragmentTransaction.addToBackStack(special_tag);
Then I simply add() fragment B on top of fragment A. After that, I decide to remove fragment B and go back to fragment A using:
activity.fragmentManager.popBackStackImmediate(special_tag, 0)
When I reach the fragment A, it seems that fragment doesn't re-run it's lifecycle methods: onAttach(), onResume(), onCreate() ect.
Can someone explain this behavior and maybe suggest an alternative?
(I need to "refresh" the data when I come back to fragment A second time)
What is causing this result?
Is there a clean solution/work-around?
Update
Fragment B is GuidedStepFragment and does not have a .replace() function. I found that it has finishGuidedStepFragments(), but it behaves the same (it does not call fragment life cycle functions)
Situation (again):
Fragment A (Simple fragment) -> .add(Fragment B) (GuidedStepFragment) -> popBackStackImmediate() or finishGuidedStepFragments()
I add Fragment B like this:
GuidedStepFragment.add(activity.fragmentManager, fragmentB.createInstance())
Using fragmentTransaction.add(Fragment) doesn't remove Fragment A. What is actually happening is that Fragment A is still running behind Fragment B. Since Fragment A never stopped running, it's lifecycle has no need to retrigger.
Consider using fragmentTransaction.replace(Fragment) and replace the fragment in the container (fragment A) with fragment B. If you pop that transaction from the back stack, then Fragment A will reattach and follow your expected lifecycle.
Update
Since you seem to be using GuidedStepFragments from the leanback library, this is a little tricky. GuidedStepFragment actually performs replace(...) under the hood, but you're adding fragment B to a different container so the original behavior I mentioned doesn't apply.
I'm not super familiar with leanback (since it's usually only used for android tv), but I do know that you can at least do the following. If you keep track of your backstack size, when all of the GuidedStepFragments have been popped, you will have returned to your original fragment. For example, let's assume your backstack starts at zero:
activity.fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (activity.fragmentManager.getBackStackEntryCount() == 0){
// handle your updates
}
}
});
// the next line of code will add an entry to the backstack
GuidedStepFragment.add(activity.fragmentManager, fragmentB.createInstance());
// eventually when back is pressed and the guided fragment is removed, the backstack listener should trigger
I have a 3 fragments:
Activity Base -> Fragment A ->Fragment B -> Fragment C
Navigation is correct between these fragments but when I do:
Activity Base -> Fragment A ->Fragment B -> Fragment C -> Activity X
I can't get a correct navigation. When I press back on Activity X it goes to Fragment A (Activity Base) and doesn't go to Fragment C.
Any ideas? Thx
Activity Base should use onSaveInstanceState to store the current active fragment. Then it has to restore that fragment in either onCreate (if the Bundle parameter is not null), or in onRestoreInstanceState.
Note (from the documentation)
Most implementations will simply use onCreate(Bundle) to restore their state, but it is sometimes convenient to do it [in onSaveInstanceState] after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation