My Android application has an ActionBar
that changes which Fragment
occupies a certain FrameLayout
. I am trying to use onSaveInstanceState
to save the state of a Fragment when the tab is changed, so that it can be recovered in onCreateView
.
The problem is, onSaveInstanceState
is never called. The Fragment
's onDestroyView
and onCreateView
methods are called, but the Bundle
supplied to onCreateView
remains null.
Can someone please explain to me when onSaveInstanceState
is actually called, how I can make sure it gets called when switching tabs, or the best practice for saving and restoring the state of a Fragment
when it is detached and re-attached?
Fragment:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.event_log, container, false);
// Retrieve saved state
if (savedInstanceState != null){
System.out.println("log retrieved");
} else {
System.out.println("log null");
}
return view;
}
@Override
public void onSaveInstanceState(Bundle outState) {
System.out.println("log saved");
super.onSaveInstanceState(outState);
// more code
}
Activity:
/**
* Detach the current Fragment, because another one is being attached.
*/
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (tab.getText().equals(getString(R.string.tab_events))){
if (frEventLog != null) {
ft.detach(frEventLog);
}
}
Fragment#onSaveInstanceState
is only called when the Activity
hosting the Fragment
is destroyed AND there is a chance that you can come back to the same activity AND the fragment is still added to the FragmentManager
. The most common case would be screen rotation.
I think your Fragment
will also need to do setRetainInstance(true)
in onCreate
for example. Not exactly sure about that point though.
You should also see this method being called when you press the home button for example. That will destroy the activity but you can go back to it by using the task list for example.
If you just detach()
the fragment all you need to do to get it back is to ask the FragmentManager
for it.
There are two examples you should have a look at:
ActionBar
FragmentTabs and TabHost
FragmentTabs
The TabHost
example uses
ft.add(containerId, fragment, tag);
// later
fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag);
to find the instances of previously added Fragment
s, works until you remove()
a Fragment
Regarding onCreateView
/ onDestroyView
: That is called once a fragment gets detached because the next time you attach it needs to create a new View
. Note that Fragment#onDetached()
is not called when you detach()
the fragment because it is still attached to the Activity
. It is only detached from the view-hierarchy.
There is another nice example on how to retain fragment state / how to use fragments to retain state in Android Training - Caching Bitmaps.
That example is missing a critical line though:
public static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
RetainFragment fragment = (RetainFragment) fm.findFragmentByTag(TAG);
if (fragment == null) {
fragment = new RetainFragment();
fm.beginTransaction().add(fragment, TAG).commit(); // << add this
}
return fragment;
}