自定义控件基础 onSaveInstanceState()

时间:2023-02-13 18:17:26

在看JakeWharton的ViewPagerIndicator时,在CircleIndicator中的onSaveInstanceState()中保存了当前的page信息,于是就学习这块。

介绍:

onSaveInstanceState()是在Activity被异常回收时会被调用,正常情况下不会调用该方法。Activity重建时会调用onRestoreInstanceState()方法,进行恢复数据。
我们在写自定义控件时,如果有必要,则要复写这两个方法。

异常情况有:

  1. 资源相关的系统配置发生改变,导致Activity被杀死并重新创建。比如旋转屏幕等。
  2. 系统资源内存不足导致低优先级的Activity被杀死。

示例:

CircleIndicator部分代码如下:
这种写法也是自定义控件时标准写法。具体可查看文章底部链接。 可以查看TextView源码,这块也是这样写的。

    @Override
//在该方法中恢复数据
public void onRestoreInstanceState(Parcelable state) {
SavedState savedState = (SavedState)state;
super.onRestoreInstanceState(savedState.getSuperState());
mCurrentPage = savedState.currentPage;
mSnapPage = savedState.currentPage;
requestLayout();
}

@Override
//在该方法中进行保存数据
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState savedState = new SavedState(superState);
savedState.currentPage = mCurrentPage;
return savedState;
}

//创建内部类,用于存储信息。继承BaseSavedState类。
static class SavedState extends BaseSavedState {
int currentPage;

public SavedState(Parcelable superState) {
super(superState);
}

private SavedState(Parcel in) {
super(in);
currentPage = in.readInt();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(currentPage);
}

@SuppressWarnings("UnusedDeclaration")
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}

@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}

另一种写法

@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable("superState", super.onSaveInstanceState());
bundle.putInt("current_item", currentItem);
bundle.putStringArray("notifications", notifications);
return bundle;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
currentItem = bundle.getInt("current_item");
notifications = bundle.getStringArray("notifications");
state = bundle.getParcelable("superState");
}
super.onRestoreInstanceState(state);
}

Fragment中:

@Override public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(EXTRA_PARCELABLE, a);
}

//可获取
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}

//可获取
@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);

}


原理:

当Activity被意外终止,Activity会调用onSaveInstanceState()去保存数据,然后Activity委托Window去保存数据。Window再委托它上面的*容器去保存数据。顶层容器是一个ViewGroup,通过他再去一一通知它的子元素来保存数据。

这篇文章 Saving Android View state correctly 更加精细的讲解了这个过程。

保存数据的条件:

  1. 必须要有ID。因为底层通过sparseArray保存数据,ViewId作为key存在。
  2. ViewId必要要独立。unique。所有状态都保存在一个sparseArray中,相同的id会造成覆盖。


参考:

能极大促进理解:
Saving Android View state correctly

自定义控件中SaveState写法:
*