1. 程式人生 > >你應該知道的Activity狀態的儲存與恢復

你應該知道的Activity狀態的儲存與恢復

本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出

首先,為了讓大家對Activity的狀態的儲存與恢復有個清楚的認識,我先舉個生活中常見的例子來說明一下,比如你去食堂吃飯,飯吃到一半的時候你突然優勢出去了一下,然後過了一會你又回來了,可是卻發現自己的飯不見了,原來是被食堂阿姨給收走了,這個時候你可能就要抱怨了,為什麼我還沒吃完就給收了,這就好比你在一個應用的一個介面執行某項操作,突然來了一個電話,當你再次回到之前那個操作介面,你發現你還要重新操作,你可能又要抱怨了,所以Activity狀態的儲存與恢復至關重要!

本文主要介紹以下知識:

第一: 有哪些狀態是需要儲存的?
第二: 什麼情況下需要Activity狀態的儲存與恢復?
第三: 狀態為什麼會丟失?
第四: 如何儲存與恢復?
第五: 這個知識點你需要注意的地方?

在正式介紹之前希望你要對Activity的生命週期有一定的瞭解!

第一: 有哪些狀態是需要儲存的?

有哪些狀態是需要儲存的呢?最簡單明瞭的就是對一些資料的儲存,比如你正在操作一些資料,當面臨突發情況,你的資料還沒有操作完,這時候你就需要將資料進行儲存,以便我們再次回到這個頁面的時候不用重頭再來。

第二: 什麼情況下需要Activity狀態的儲存與恢復?

那麼在什麼情況下需要對Activity的狀態進行儲存與恢復呢?官方文件的說法是在處理執行時配置變更的時候,來看官方文件介紹的一段話

有些裝置配置可能會在執行時發生變化(例如螢幕方向、鍵盤可用性及語言)。 發生這種變化時,Android 會重啟正在執行的 Activity(先後呼叫 onDestroy() 和 onCreate())。重啟行為旨在通過利用與新裝置配置匹配的備用資源自動重新載入您的應用,來幫助它適應新配置。
要妥善處理重啟行為,Activity 必須通過常規的Activity 生命週期恢復其以前的狀態,在 Activity 生命週期中,Android 會在銷燬 Activity 之前呼叫 onSaveInstanceState(),以便您儲存有關應用狀態的資料。 然後,您可以在 onCreate() 或 onRestoreInstanceState() 期間恢復 Activity 狀態。

這裡面提到了各種回撥方法,其中也有本文介紹的重點,不急,我們一步步來,首先我總結有如下幾種情況是需要對資料進行儲存的
1. 點選了返回鍵
2. 鎖屏
3. 點選home鍵
4. 有其他APP進入前臺(比如接聽電話)
5. 啟動了新的Activity
6. 螢幕方向發生旋轉
7. APP被殺死

第三: 狀態為什麼會丟失?

緊接著,我們來說一下為什麼狀態會丟失,這裡面到底發什麼了什麼操作?這裡我們用程式碼來演示一下,就是一個Activity,我們複寫它的onCreat和onDestroy方法,分別打上log,然後啟動再點選旋轉螢幕(本文主要以螢幕旋轉為例)看看這個過程方法是如何執行的。

11-25 12:51:27.419 4153-4153/com.ithuangqing.activitysavedemo D/mainactivity--vv: onCreate
11-25 12:51:33.459 4153-4153/com.ithuangqing.activitysavedemo D/mainactivity--vv: onDestroy
11-25 12:51:33.539 4153-4153/com.ithuangqing.activitysavedemo D/mainactivity--vv: onCreate

我們從log中可知,當應用啟動,首先執行onCreat方法,當我們點選旋轉螢幕會發現當前的Activity被銷燬了,然後又重新執行了onCreat方法,這是怎麼回事,Activity發生了什麼樣的變化呢?我們在log中打印出當前Activity的hashcodekankan。

11-25 12:57:20.934 4439-4439/com.ithuangqing.activitysavedemo D/mainactivity--vv: onCreatecom.ithuangqing.activitysavedemo.MainActivity@4a79f318
11-25 12:57:26.184 4439-4439/com.ithuangqing.activitysavedemo D/mainactivity--vv: onDestroycom.ithuangqing.activitysavedemo.MainActivity@4a79f318
11-25 12:57:26.224 4439-4439/com.ithuangqing.activitysavedemo D/mainactivity--vv: onCreatecom.ithuangqing.activitysavedemo.MainActivity@4a7d4274

原來當點選了螢幕旋轉之後,當前Activity會被銷燬,然後會重新建立一個新的Activity,如此一來我們在之前Activity的資料如果不儲存的話就又可能丟失了。

好了,到了這一步你至少要明白這麼一件事,就是當在第二部分中說的幾種情況出現時比如螢幕發生旋轉,當前的Activity會被銷燬而且會重新建立一個全新的Activity。

下面我們舉一個數據丟失的例子,讓你看的更清楚。首先設定佈局,佈局很簡單,一個文字框,一個按鈕,給按鈕設定一個點選事件,點選按鈕讓文字框中的數字從一遞增。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMNumber = findViewById(R.id.number);
        mBtAdd = findViewById(R.id.btAdd);
        mBtAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                a = ++a;
                mMNumber.setText(""+a);
            }
        });
        Log.d(TAG, "onCreate"+this);
    }

執行之後點選按鈕,如圖
這裡寫圖片描述

現在文字框中的數字是5,接下來我們點選螢幕旋轉看看會發生什麼,如圖
這裡寫圖片描述

果不其然,資料丟失了。

第四: 如何儲存與恢復?

既然資料會丟失,那麼我們該如何儲存資料,或者如何解決這些問題呢?我們拿螢幕旋轉這個變更來說,首先我們知道,如果螢幕發生旋轉,當前Activity會被銷燬,因此我們可以限定螢幕的方向,這樣一來即使我們點選螢幕旋轉,螢幕的方向是沒有發什麼變化的,所以Activity不會被銷燬,資料自然不會丟失,另外一種方法就是我們可以自己處理變更,我們可以在當前的Activity的配置檔案中新增這麼一行程式碼

 android:configChanges="orientation|screenSize|keyboard"

這句程式碼的意思就是告訴系統我們自己來處理變更,這兩種方法不是今天的主菜,真正的主菜是onSaveInstanceState和onRestoreInstanceState,終於說到我們的重點了,我相信看完本文的介紹,大家會對這個東西有種終於認識的感覺,那就是每次建立Axtivity中自動建立的onCreat方法中的引數

Bundle savedInstanceState

首先我們在我們的Acticiry中複寫onSaveInstanceState和onRestoreInstanceState同時打上log。看一下 輸出。

11-25 13:38:57.383 5242-5242/com.ithuangqing.activitysavedemo D/mainactivity--vv: onCreate
11-25 13:39:13.133 5242-5242/com.ithuangqing.activitysavedemo D/mainactivity--vv: onSaveInstanceState
11-25 13:39:13.133 5242-5242/com.ithuangqing.activitysavedemo D/mainactivity--vv: onDestroy
11-25 13:39:13.163 5242-5242/com.ithuangqing.activitysavedemo D/mainactivity--vv: onCreate
11-25 13:39:13.163 5242-5242/com.ithuangqing.activitysavedemo D/mainactivity--vv: onRestoreInstanceState

從log中我們可以看到,當我們點選螢幕旋轉之後,在當前Activity被銷燬之前會呼叫onSaveInstanceState,然後銷燬當前Activity,建立新的Activity之後會呼叫onCreat方法之後會緊接著呼叫onRestoreInstanceState,那麼這兩個方法有什麼用呢?其實也可以猜到,onSaveInstanceState是用來儲存我們當前activity中的資料的,而onRestoreInstanceState可以讓我們獲取之前儲存的資料從而在新的activity中進行設定。

那資料以何種形式進行儲存呢?我們來看下這兩個函式

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //儲存銷燬之前的資料

        Log.d(TAG, "onSaveInstanceState");

    }

   @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onRestoreInstanceState");
    }

我們發現他們的引數是Bundle,有印象了吧!我們就是通過Bundle來進行資料儲存和讀取的,大家都知道這是一種鍵值對的儲存與讀取方式。

接下來再看一個函式

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mMNumber = findViewById(R.id.number);
        mBtAdd = findViewById(R.id.btAdd);
        mBtAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                a = ++a;
                mMNumber.setText(""+a);
            }
        });
        Log.d(TAG, "onCreate");
    }

看看onCreat函式的引數,你發現了什麼嘛?前面說過我們可以在onRestoreInstanceState中通過Bundle拿到我們之前儲存的資料,其實在onCreat中也能達到相同的效果。
下面我們就具體程式碼演示一遍吧!

首先是在onSaveInstanceState中儲存資料

   @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //儲存銷燬之前的資料
        outState.putString("number",mMNumber.getText().toString());
        Log.d(TAG, "onSaveInstanceState");

    }

緊接著在onRestoreInstanceState對資料進行恢復

   @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onRestoreInstanceState");
        //恢復資料
       String s = savedInstanceState.getString("number");
       mMNumber.setText(s);
    }

接下來執行程式

這裡寫圖片描述

然後我們旋轉螢幕

這裡寫圖片描述

發現數據被成功保留了下來,

到這裡我們總結一下這個方法的呼叫過程,當執行時配置發生變更的時候,程式總的會銷燬當前的Activity,然後重新建立一個新的Activity,在這個過程中,銷燬當前Activity之前會先呼叫onSaveInstanceState讓我們來儲存資料,然後重建Activity在呼叫onCreat方發之後會呼叫onRestoreInstanceState讓我們來對資料進行恢復,當然也可以在onCret中進行資料恢復,方法原理相同。

第五: 這個知識點你需要注意的地方?

通過以上的講訴,相信你對Activity狀態的儲存與恢復已經掌握的差不多了,在這裡我再補充幾點
1. 關於onSaveInstanceState
這個方法預設情況下會自動儲存有關Activity的檢視層次結構的狀態資訊,簡單舉個例子,我們以系統控制元件EditText來說,系統預設會儲存有關這個控制元件的一個資訊,也就是當你在這個控制元件中輸入內容的時候,即使旋轉螢幕內容也不會丟失,因為系統已經預設為其實現了我們說的那兩個方法,但是有個前提,這個控制元件必須設定id,否則資料依舊會丟失,另外如果你重寫了onRestoreInstanceState也要保證必須有這行程式碼

super.onRestoreInstanceState(savedInstanceState);
  1. 關於旋轉螢幕無法呼叫onSaveInstanceState的問題。

出現這種問題你複寫的肯定以下方法

public void onSaveInstanceState (Bundle outState, PersistableBundle outPersistentState); 

改成以下方法即可

 public void onSaveInstanceState (Bundle outState);

結束
關於Activity狀態的儲存與恢復其實還有很多值得研究的問題,本文暫且介紹到這裡,學無止境,希望對你有幫助,我是一個自學的程式設計師,我為自己代言!