How does `onViewStateRestored` from Fragments work?

Rafael T picture Rafael T · Jul 22, 2013 · Viewed 16.8k times · Source

I am really confused with the internal state of a Fragment. I have an Activity holding only one Fragment at once and replaces it, if another Fragment should get shown. From the docs onSaveInstanceState is called ONLY if the Activitys onSaveInstanceState is getting called (which isn't called in my case).

If I stop my Fragment, I'll store its state myself inside a Singleton (yeah, I know I hate Singletons, too, but wasn't my idea to do so). So I have to recreate the whole ViewHirarchy, create new Views (by using the keyword new), restore its state and return them in onCreateView. I also have a Checkbox inside this View from which I explicitly do NOT want to store its state.

However the FragmentManager wants to be "intelligent" and calls onViewStateRestored with a Bundle I never created myself, and "restores" the state of the old CheckBox and applies it to my NEW CheckBox. This throws up so many questions:

Can I control the bundle from onViewStateRestored?

How does the FragmentManager take the state of a (probably garbage-collected) CheckBox and applies it to the new one?

Why does it only save the state of the Checkbox (Not of TextViews??)

So to sum it up: How does onViewStateRestored work?

Note I'm using Fragmentv4, so no API > 17 required for onViewStateRestored

Answer

Victor A. Parcianello Benso picture Victor A. Parcianello Benso · Aug 28, 2015

Well, sometimes fragments can get a little confusing, but after a while you will get used to them, and learn that they are your friends after all.

If on the onCreate() method of your fragment, you do: setRetainInstance(true); The visible state of your views will be kept, otherwise it won't.

Suppose a fragment called "f" of class F, its lifecycle would go like this: - When instantiating/attaching/showing it, those are the f's methods that are called, in this order:

F.newInstance();
F();
F.onCreate();
F.onCreateView();
F.onViewStateRestored;
F.onResume();

At this point, your fragment will be visible on the screen. Assume, that the device is rotated, therefore, the fragment information must be preserved, this is the flow of events triggered by the rotation:

F.onSaveInstanceState(); //save your info, before the fragment is destroyed, HERE YOU CAN CONTROL THE SAVED BUNDLE, CHECK EXAMPLE BELLOW.
F.onDestroyView(); //destroy any extra allocations your have made
//here starts f's restore process
F.onCreateView(); //f's view will be recreated
F.onViewStateRestored(); //load your info and restore the state of f's view
F.onResume(); //this method is called when your fragment is restoring its focus, sometimes you will need to insert some code here.


//store the information using the correct types, according to your variables.
@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("foo", this.foo);
    outState.putBoolean("bar", true);
}

@Override
public void onViewStateRestored(Bundle inState) {
    super.onViewStateRestored(inState);
    if(inState!=null) {
        if (inState.getBoolean("bar", false)) {
            this.foo = (ArrayList<HashMap<String, Double>>) inState.getSerializable("foo");
        }
    }

}