Activity異常銷毀狀態(tài)下的數(shù)據(jù)保存與恢復(fù)

在一些極端情況下我們的Activity會(huì)被銷毀然后重建:例如內(nèi)存不足時(shí),我們界面被回收,APP在回到前臺(tái)時(shí)系統(tǒng)根據(jù)棧信息為APP重新創(chuàng)建Activity,或者在屏幕旋轉(zhuǎn)時(shí)Activity會(huì)重新創(chuàng)建。在重建的時(shí)候系統(tǒng)會(huì)默認(rèn)為我們恢復(fù)一些狀態(tài),如果不了解沒(méi)有處理就可能會(huì)出現(xiàn)一些預(yù)料不到的錯(cuò)誤,數(shù)據(jù)的恢復(fù)和存儲(chǔ)包括兩方面:Activity和View

一、Activity的數(shù)據(jù)保存和恢復(fù)

在界面異常銷毀之前會(huì)先調(diào)用onSaveInstanceState保存數(shù)據(jù),這個(gè)方法一般是在onPause之后調(diào)用,我們可以在這個(gè)地方保存當(dāng)前界面的數(shù)據(jù)和界面狀態(tài)。當(dāng)系統(tǒng)為我們重新創(chuàng)建Activity的時(shí)候,系統(tǒng)會(huì)調(diào)用onCreateonRestoreInstanceState講保存的數(shù)據(jù)返回給我們,我們從中取出保存的數(shù)據(jù)來(lái)為用戶恢復(fù)到崩潰前的界面,這里有一點(diǎn)要注意的是,onCreate每個(gè)創(chuàng)建都會(huì)被調(diào)用,而onRestoreInstanceState只有在onSaveInstanceState調(diào)用之后的創(chuàng)建才會(huì)被調(diào)用,開(kāi)發(fā)者可以根據(jù)需求自己權(quán)衡使用哪個(gè)方法來(lái)恢復(fù)數(shù)據(jù)

二、View的數(shù)據(jù)保存和恢復(fù)

對(duì)于View的重建比較特殊一點(diǎn),因?yàn)橄到y(tǒng)已經(jīng)為我們實(shí)現(xiàn)好了一部分工作,所以這個(gè)地方分成2部分:

1、系統(tǒng)默認(rèn)控件

Android默認(rèn)控件都已經(jīng)為我們實(shí)現(xiàn)了數(shù)據(jù)保存和恢復(fù)機(jī)制,但是大部分都沒(méi)有開(kāi)啟這個(gè)機(jī)制,需要我們自己去控制,例如TextView,首先我們來(lái)看保存代碼:

    @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;
            }
        }

        //判斷并保存當(dāng)前的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;
            }
            
            //保存是否有焦點(diǎn)
            if (isFocused() && start >= 0 && end >= 0) {
                ss.frozenWithFocus = true;
            }
            
            //保存錯(cuò)誤信息
            ss.error = getError();
            
            //保存編輯狀態(tài)
            if (mEditor != null) {
                ss.editorState = mEditor.saveInstanceState();
            }
            return ss;
        }

        return superState;
    }

從上述代碼和注釋中可以看到當(dāng)freezesTextTrue時(shí)就會(huì)保存Text,所以可以這么設(shè)置

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

2、自定義控件的數(shù)據(jù)保存和恢復(fù)

因?yàn)樽远x控件的數(shù)據(jù)不確定性,導(dǎo)致保存和恢復(fù)的邏輯只能我們自己來(lái)實(shí)現(xiàn),但是也不會(huì)脫離View的范圍。下面以例子來(lái)說(shuō)明實(shí)現(xiàn)方法:

1、保存數(shù)據(jù)的Model,這個(gè)要繼承基礎(chǔ)類

   private static class PercentSaveState extends BaseSavedState {

        private int mReachColor; // 達(dá)到的百分比顏色

        private int mUnReachColor; // 沒(méi)有達(dá)到的百分比顏色

        private int mPercentTextColor;// 百分比數(shù)據(jù)的顏色

        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];
            }


        };

    }

這個(gè)主要是在保存數(shù)據(jù)的時(shí)候,要對(duì)數(shù)據(jù)進(jìn)行序列化準(zhǔn)備的

2、保存數(shù)據(jù)

    @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、恢復(fù)數(shù)據(jù)

    @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();
    }

實(shí)現(xiàn)方法比較簡(jiǎn)單,但是有一點(diǎn)需要注意,在onRestoreInstanceState中一定要調(diào)用super.onRestoreInstanceState否則會(huì)報(bào)錯(cuò),其原因就在我們繼承的BaseSavedState中。在BaseSavedState中,系統(tǒng)還為我們處理了一個(gè)變量mStartActivityRequestWhoSaved的存取,這個(gè)變量是用來(lái)接收startActivityForResult處理結(jié)果的標(biāo)示符,因此不能再重建的時(shí)候進(jìn)行改變。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容