自定义控件基础 onSaveInstanceState()

来源:互联网 发布:php程序员职业规划 编辑:程序博客网 时间:2024/06/03 17:52

在看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写法:
stackoverflow

0 0
原创粉丝点击