日常的开发过程中难免会自定义一些view,view的状态数据保存及恢复也是需要考虑进内的,就会用到onSaveInstanceState和onRestoreInstanceState这两个方法。
onSaveInstanceState
顾名思义,保存实例状态。以CompoundButton为例:
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.checked = isChecked();
return ss;
}
该方法返回的是一个序列化对象,即SavedState,checked状态也是保存在该对象里面,看一下该类的实现:
static class SavedState extends BaseSavedState {
boolean checked;
/**
* Constructor called from {@link CompoundButton#onSaveInstanceState()}
*/
SavedState(Parcelable superState) {
super(superState);
}
/**
* Constructor called from {@link #CREATOR}
*/
private SavedState(Parcel in) {
super(in);
checked = (Boolean)in.readValue(null);
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeValue(checked);
}
@Override
public String toString() {
return "CompoundButton.SavedState{"
+ Integer.toHexString(System.identityHashCode(this))
+ " checked=" + checked + "}";
}
@SuppressWarnings("hiding")
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
代码简单,整个类即是序列化的实现,该类继承BaseSavedState,BaseSavedState在View里面定义,用于保存View的状态。BaseSavedState继承AbsSavedState,AbsSavedState则实现了Parcelable。代码就不贴了,在我们的自定义view里面,比葫芦画瓢,也实现一个继承BaseSavedState的类,把需要保存的状态利用该类保存即可。
onRestoreInstanceState
顾名思义,恢复实例状态。还是看CompoundButton的代码:
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
setChecked(ss.checked);
requestLayout();
}
onSaveInstanceState返回的是SavedState对象,该方法会将SavedState对象传递过来,强制类型转换之后,先将父View的状态恢复过去,再从该对象里面拿到之前保存的状态进行恢复即可。
以上即是自定义view的状态保存的基本用法,到这里还不够,我们需要阅读一下源码,看一下如上两个方法是如何调用的,才能知其然,遇到问题时知道如何分析。
源码分析
所有的view的根view均是android.view.View,可以从这里下手看看上面两个方法是怎么调用的。调用onSaveInstanceState的代码如下:
/**
* Store this view hierarchy's frozen state into the given container.
*
* @param container The SparseArray in which to save the view's state.
*
* @see #restoreHierarchyState(android.util.SparseArray)
* @see #dispatchSaveInstanceState(android.util.SparseArray)
* @see #onSaveInstanceState()
*/
public void saveHierarchyState(SparseArray<Parcelable> container) {
dispatchSaveInstanceState(container);
}
/**
* Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for
* this view and its children. May be overridden to modify how freezing happens to a
* view's children; for example, some views may want to not store state for their children.
*
* @param container The SparseArray in which to save the view's state.
*
* @see #dispatchRestoreInstanceState(android.util.SparseArray)
* @see #saveHierarchyState(android.util.SparseArray)
* @see #onSaveInstanceState()
*/
protected void dispatchSaveInstanceState