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.
Related
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.
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
CONSTRUCTION
Activity A holds Fragment A that is able add Fragment B on backstack.
PROBLEM
Fragment B holds Views generated via API response.
State of these Views is what I need to be able to recreate after rotation or when going back to Fragment A by using onBackPressed and lunching Fragment B again.
I've read quite some of the topics on SO about Fragments in backstack and I am aware of their inability to retain instance.
What should I do to achieve such outcome?
Fragments on backstack can always retain instance if you save it. An Activity or a Fragment on a backstack in simply in a paused state. So you want to save the data/variables in the onSaveInstanceState method for that class (you will be overriding it).
Now to restore from the saved state you would have noticed that the onCreate, onCreateView for Activity, Fragment, respectively, have a Bundle savedInstanceState parameter being passed in. This is where you saved your state in the previous step, thus, you can add
if (savedInstanceState != null) {
//TODO: restore the state
}
to your onCreate/onCreateView method and you should be good to go.
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();
I have some king of header in my activity, which says what kind of fragment is opened now. It's ok, when I'm just replacing one fragment by another, but I have a problem with handling backstack changes in onBackPressed. That's a part of my code in onBackPressed method:
Fragment fragment = fragmentManager.findFragmentById(R.id.main_fragment);
fragmentManager.popBackStack();
fragment = fragmentManager.findFragmentById(R.id.main_fragment);
in first row, fragment=FormFragment{41f01d58 #3 id=0x7f05005f}, and after calling popBackStack I have fragment=FormFragment{41f01d58 #3 id=0x7f05005f} again (but it should be another fragment, even not FormFragment instance).
Is there any way how to find out what fragment is popped from backstack after calling popBackStack?
First of all, usually you don't have to pop the fragment back stack yourself. If your activity is a FragmentActivity, its default onBackPressed() will do the work for you.
To update your header when the fragment is popped from the back stack, put the header update code in the fragment's onResume().