I have a instance of FragmentManager (variable frgManager), I replace to new fragment by:
// Fragments all use the same container
frgManager.beginTransaction().replace(containerId, nextFragment, MyTag).commit();
Let's say I have three fragments A, B, C,
the app show fragments in the sequence of A-->B-->C. Everytime show next fragment, I call the code above.
The problem is after C is shown, I close C, then B is shown in foreground, but the onResume() of A is also called. Why? How to avoid that because I expect only B's onResume() get called in this case.
frgManager.beginTransaction().replace(containerId, nextFragment, MyTag).addToBackStack().commit();
Use addToBackStack when creating all of your fragments. This way, only 1 can be active at once.
Related
I'm using MVP in my project. I have an activity. Inside this activity I'm showing fragment. Fragment contains some data, edit text, buttons etc. From this fragment it is possible to navigate to another fragment. Here is my code for showing another fragment:
getParentFragmentManager()
.beginTransaction()
.replace(R.id.main_container, secondFragment)
.addToBackStack(null)
.commitAllowingStateLoss();
Next, when I try to go back from fragment 2 to fragment 1, my fragment one is re-created.The method onViewCreated() is called again with saveedInstanceState = null. Also in the onViewCreated() I call presenter.onCreate(savedInstanceState) and because of this, all requests that should be called when I first enter the fragment are re-called when I back to first fragment.
As far as I understand, when calling a .replace(container, fragment), I cannot avoid recreating the fragment view, but in this case, how can I save all my data in the presenter so that I do not re-execute all requests when returning to the fragment?
P.S. With .add() fragment is not recreated. But in my activity I have toolbar with title, and I don't need it to show in my second fragment. When I open my second fragment with .replace() toolbar is not showing, but when open with .add() toolbar is showing.
Use Fragment Result API :
For implemention this method set - setFragmentResultListener - in source fragment and also set - setResult() and finish() - in destination fragment
Note 1 : for having clean code i suggest you to use FragmentTransaction class in:
https://github.com/mahditavakoli1312/FragmentTransaction---mahdi-tavakoli
Note 2 : use Navigation for navigate betwin fragments and activities Instead tranastion
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).
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 two activities, A and B.
Activity A, has one fragment F, added dynamically via a transaction. From F, I start activity B (F.getActivity.startActivity(intent)). When I press the back button, F gets recreated. Can I avoid that?
If not, I understand I can save the fragment state, but the savedInstanceState bundle is always null. I found you must set an id in the XML, but as the fragment is dynamically created, I don't know how to set it.
Thanks.
you can manage it by adding fragment to backstack by below code
fragmentTransaction.add(R.id.containerView, fragment);
fragmentTransaction.addToBackStack("test");
and pop back the fragment state by below one
fragmentManager.popBackStack("test", FragmentManager.POP_BACK_STACK_INCLUSIVE);
hope this will be helpful.
I have an activity within it I do
FragmentTransaction trans = getFragmentManager().beginTransaction();
FragmentList fragList = new FragmentList();
trans.replace(R.id.fragList, fragList, "fragList");
to fill my frame layout with the actual fragment. That works fine. Through navigation I end up later in some other activity and some other fragment. In that new fragment I have to call a method of my list fragment to tell it that something has changed.
FragmentList listfrag = (FragmentList) getFragmentManager().findFragmentByTag("fragList");
FragmentList listfrag2 = (FragmentList) getFragmentManager().findFragmentById(R.id.fraglist);
listfrag.updateData(b);
Both, listfrag and listfrag2, are always null. Why?
Edit:
based on the answer that this is not possible from one activity to another activity. I have activity A,
On a tablet A has fragment F1 and F2, on a phone only F1. If I select something on F1, the either F2 gets updated or activity B is called to show F2. In F2 I press a save button and I want to update F1 based. So I either have to call something in the same activity (tablet) or in different acitivty (phone). How can I do this without duplicating my code for the updates?
The getFragmentManager() method gets a reference to the FragmentManager that is used within that activity.
In essence, you are creating the Fragment in one Activity, but looking for it in another. You can't do that (easily).
It sounds like you might want to use startActivityForResult() and onActivityResult() to pass data back and forth between the Activities.
Fragment lifecycle is tied to its activity, you can't call it from another activity. But in the same activity when you replace with another fragment,
Try this,
trans
.replace(R.id.fragList, fragList, "fragList")
.addToBackStack(null) // this will keep fragment when you replace with another.
.commit();