-
Notifications
You must be signed in to change notification settings - Fork 55
State saving
View's state should carry the information needed to restore the view's look. It shouldn't contain the application's state. For example, if you have a Button that is disabled while the application is loading something, that's the application's state. The Button shouldn't save its disabled state in this case. Android views save only a couple of things: EditText's text, CheckBox'es/RadioButton's checked state, ListView's selection, etc.
To save its state the view also needs to have a unique id set. Ids are used by views' parents to store states in a map. Having two or more views with the same id in one container will result in state loss and may cause IllegalArgumentException
if the views are of different types.
You can also turn state saving on and off using android:saveEnabled
and isSaveEnabled()
/setSaveEnabled()
. State saving is enabled by default.
It's one of the things you don't really ever remember and always copy from other projects. This example comes from my CheckBox class. To save the state you need to override onSaveInstanceState()
and write values you'd like to save to a Parcelable
. The superclass may have stored some data already, so you have to take it and pass it on.
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.checked = checkedState;
return ss;
}
The corresponding onRestoreInstanceState()
reads the state from a Parcelable
and sets it to the view. Remember to read values in the order of writing.
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setChecked(ss.checked);
}
The last part is the custom SavedState
class used to read and write the state. The class has a constructor to use with a state of the view's superclass, a constructor to read the state from a Parcel
object and a static factory (the CREATOR
field) used by the Android framework internally. The most interesting things happen in the Parcel
constructor (value reading) and in the writeToParcel()
method (value writing).
static class SavedState extends BaseSavedState {
boolean checked;
SavedState(Parcelable superState) {
super(superState);
}
private SavedState(Parcel in) {
super(in);
checked = in.readBoolean();
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeBoolean(checked);
}
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
ViewGroup and its descendants also support saving their hierarchy states. In other words, these classes save their own state and the states of their children by dispatching save/restore state events to them. There's a couple of methods for that:
-
saveHierarchyState()
/restoreHierarchyState()
start state saving/restoring. These methods can be called to save/restore the state to/from aSparseArray<Parcelable>
. -
dispatchSaveInstanceState()
/dispatchRestoreInstanceState()
dispatch the events to the group's children.
Usually, there's no need to interfere with these methods. The ViewGroup
's implementation is very simple (iterates over children) and is used without changes by layouts.