美文网首页
Activity异常销毁状态下的数据保存与恢复

Activity异常销毁状态下的数据保存与恢复

作者: Aracys | 来源:发表于2017-04-27 17:06 被阅读848次

在一些极端情况下我们的Activity会被销毁然后重建:例如内存不足时,我们界面被回收,APP在回到前台时系统根据栈信息为APP重新创建Activity,或者在屏幕旋转时Activity会重新创建。在重建的时候系统会默认为我们恢复一些状态,如果不了解没有处理就可能会出现一些预料不到的错误,数据的恢复和存储包括两方面:Activity和View

一、Activity的数据保存和恢复

在界面异常销毁之前会先调用onSaveInstanceState保存数据,这个方法一般是在onPause之后调用,我们可以在这个地方保存当前界面的数据和界面状态。当系统为我们重新创建Activity的时候,系统会调用onCreateonRestoreInstanceState讲保存的数据返回给我们,我们从中取出保存的数据来为用户恢复到崩溃前的界面,这里有一点要注意的是,onCreate每个创建都会被调用,而onRestoreInstanceState只有在onSaveInstanceState调用之后的创建才会被调用,开发者可以根据需求自己权衡使用哪个方法来恢复数据

二、View的数据保存和恢复

对于View的重建比较特殊一点,因为系统已经为我们实现好了一部分工作,所以这个地方分成2部分:

1、系统默认控件

Android默认控件都已经为我们实现了数据保存和恢复机制,但是大部分都没有开启这个机制,需要我们自己去控制,例如TextView,首先我们来看保存代码:

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();

        // Save state if we are forced to
        final boolean freezesText = getFreezesText();
        boolean hasSelection = false;
        int start = -1;
        int end = -1;

        if (mText != null) {
            start = getSelectionStart();
            end = getSelectionEnd();
            if (start >= 0 || end >= 0) {
                // Or save state if there is a selection
                hasSelection = true;
            }
        }

        //判断并保存当前的Text
        if (freezesText || hasSelection) {
            SavedState ss = new SavedState(superState);

            if (freezesText) {
                if (mText instanceof Spanned) {
                    final Spannable sp = new SpannableStringBuilder(mText);

                    if (mEditor != null) {
                        removeMisspelledSpans(sp);
                        sp.removeSpan(mEditor.mSuggestionRangeSpan);
                    }

                    ss.text = sp;
                } else {
                    ss.text = mText.toString();
                }
            }

            if (hasSelection) {
                // XXX Should also save the current scroll position!
                ss.selStart = start;
                ss.selEnd = end;
            }
            
            //保存是否有焦点
            if (isFocused() && start >= 0 && end >= 0) {
                ss.frozenWithFocus = true;
            }
            
            //保存错误信息
            ss.error = getError();
            
            //保存编辑状态
            if (mEditor != null) {
                ss.editorState = mEditor.saveInstanceState();
            }
            return ss;
        }

        return superState;
    }

从上述代码和注释中可以看到当freezesTextTrue时就会保存Text,所以可以这么设置

<TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:freezesText="true" />

2、自定义控件的数据保存和恢复

因为自定义控件的数据不确定性,导致保存和恢复的逻辑只能我们自己来实现,但是也不会脱离View的范围。下面以例子来说明实现方法:

1、保存数据的Model,这个要继承基础类

   private static class PercentSaveState extends BaseSavedState {

        private int mReachColor; // 达到的百分比颜色

        private int mUnReachColor; // 没有达到的百分比颜色

        private int mPercentTextColor;// 百分比数据的颜色

        private float mCircleWidth;// 圆形框的宽度

        private float mPercent;// 百分比

        PercentSaveState(Parcel source) {
            super(source);
            mReachColor = source.readInt();
            mUnReachColor = source.readInt();
            mPercentTextColor = source.readInt();
            mCircleWidth = source.readFloat();
            mPercent = source.readFloat();
        }


         PercentSaveState(Parcelable superState) {
            super(superState);
        }

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(mReachColor);
            out.writeInt(mUnReachColor);
            out.writeInt(mPercentTextColor);
            out.writeFloat(mCircleWidth);
            out.writeFloat(mPercent);
        }

        public static final Parcelable.Creator<PercentSaveState> CREATOR = new Parcelable.Creator<PercentSaveState>() {

            @Override
            public PercentSaveState createFromParcel(Parcel source) {
                return new PercentSaveState(source);
            }

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


        };

    }

这个主要是在保存数据的时候,要对数据进行序列化准备的

2、保存数据

    @Override
    protected Parcelable onSaveInstanceState() {
        Log.i(TAG, "onSaveInstanceState: ");
        Parcelable superState = super.onSaveInstanceState();
        PercentSaveState saveState = new PercentSaveState(superState);
        saveState.mPercent = mPercent;
        saveState.mCircleWidth = mCircleWidth;
        saveState.mPercentTextColor = mPercentTextColor;
        saveState.mUnReachColor = mUnReachColor;
        saveState.mReachColor = mReachColor;
        return saveState;
    }

3、恢复数据

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        Log.i(TAG, "onRestoreInstanceState: ");
        if (!(state instanceof PercentSaveState)) {
            super.onRestoreInstanceState(state);
        }
        PercentSaveState saveState = (PercentSaveState) state;
        super.onRestoreInstanceState(saveState.getSuperState());
        mCircleWidth = saveState.mCircleWidth;
        mPercent = saveState.mPercent;
        mReachColor = saveState.mReachColor;
        mUnReachColor = saveState.mUnReachColor;
        mPercentTextColor = saveState.mPercentTextColor;
        invalidate();
    }

实现方法比较简单,但是有一点需要注意,在onRestoreInstanceState中一定要调用super.onRestoreInstanceState否则会报错,其原因就在我们继承的BaseSavedState中。在BaseSavedState中,系统还为我们处理了一个变量mStartActivityRequestWhoSaved的存取,这个变量是用来接收startActivityForResult处理结果的标示符,因此不能再重建的时候进行改变。

相关文章

网友评论

      本文标题:Activity异常销毁状态下的数据保存与恢复

      本文链接:https://www.haomeiwen.com/subject/vtmpzttx.html