Reputation: 3561
I read the many posts that have already dealt with similar issues but haven't been able to find something that answers my question completely.
I have an Android app that uses nested fragments (from the v4 support library). I have a main FragmentActivity that contains a fragment, and that fragment contains a ViewPager which enables swiping between 3 internal fragments. I'd like to be able to save the state of each of the 3 internal nested fragments, and for that I overrode the onSaveInstanceState() method for each of the 3 internal fragments and attempted to restore the state in onActivityCreated(), like so:
InternalFragment1.java:
public class InternalFragment1 extends Fragment {
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
// Commands to attach to main UI components...
if(savedInstanceState != null) {
// Commands to restore the saved state...
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
// Commands to save the state into outState...
super.onSaveInstanceState(outState);
}
}
However when onActivityCreated()
is called, savedInstanceState is always null, regardless of whether a saved state exists or not.
I should also point out that calling this.setRetainInstance()
throws an exception stating: "Can't retain fragments that are nested in other fragments".
How can I properly save and restore the nested fragments' state?
Upvotes: 2
Views: 6229
Reputation: 21
I had a similar issue and was looking for hints on solving it. Eventually, I realized that my parent fragment's onCreateView included:
mChildFragment = ChildFragment.newInstance(mId);
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, mChildFragment).commit();
This, of course, creates a new instance of the child fragment, which has a null bundle for the savedInstanceState. Surrounding the above block with a conditional:
if(savedInstanceState == null) {
mChildFragment = ChildFragment.newInstance(mId);
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, mChildFragment).commit();
}
seems to make it work, in that now the onCreate in the child fragment sees the non-null savedInstanceState I created for it in onSaveInstanceState, and is restored to how I want it.
Upvotes: 2
Reputation: 1065
There doesn't seem to be a simple way for a nested fragment to retain information. My solution was to have the parent fragment hold onto a map of Bundles and the nested fragments get their own during onCreate. The biggest issue with this is you can't have more than one instance of each nested fragment.
Ex (sorry this is in Kotlin, but it's the same thing in Java)
class ParentFragment : Fragment(), ParentFragmentListener {
val bundles = SparseArray<Bundle>()
fun getChildBundle(fragmentId : Int) : Bundle {
if (bundles.get(fragmentId) == null) {
val bundle = Bundle()
bundles.put(fragmentId,bundle)
return bundle
}
return bundles.get(fragmentId)
}
}
interface ParentFragmentListener {
fun getChildBundle(fragmentId : Int) : Bundle
}
class ChildFragment : Fragment() {
lateinit var childBundle : Bundle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val listener = parentFragment as? ParentFragmentListener
val childBundle = listener?.getFragmentsSavedBundle(UNIQUE_FRAGMENT_ID)
if (childBundle != null) this.childBundle = childBundle else childBundle = Bundle()
}
}
Upvotes: 0
Reputation: 481
That's a problem you may encounter when the parent fragment is retaining.
You can try this: http://ideaventure.blogspot.lu/2014/10/nested-retained-fragment-lost-state.html
But I would better recommend removing the setRetaining() on the parentFragment.
Upvotes: 0
Reputation: 1192
if you use setRetainInstance(true) then of course the bundle is null.
The fragment is not destroyed but only detached from the current activity and attached to the new activity. Only when the fragment is destroyed, you get a bundle with the values you saved in onSaveInstanceState.
Just try to remove setRetainInstance(true).
Upvotes: 0