天天看點

Android中onSaveInstanceState和onRestoreInstanceState(附帶工程源碼)

 在Android系統中,有時系統可能因為系統資源不夠而殺死(kill)某些Activity,在kill Activity之前會調用 onSaveInstanceState來儲存一些狀态資訊(當然也可以儲存其他資訊),當再次回到該Activity時,系統會調用onRestoreInstanceState來恢複資料。

     下面先講一下onSaveInstance的調用時機,也就是會在什麼情況下被調用。onSaveInstance不是Activity正常生命周期裡面的函數。在Google API文檔上是這樣介紹的: Android calls onSaveInstanceState() before the activity becomesvulnerable to being destroyed by the system, but does not bother calling itwhen the instance is actually being destroyed by a user action (such aspressing the BACK key)。也就是當某個activity變得“容易”被系統銷毀時,該activity的onSaveInstanceState就會被執行,除非該activity是被使用者主動銷毀的該方法不會調用,例如當使用者按BACK鍵的時候。“容易”包含以下幾種情況:

1、當使用者按下HOME鍵時。當按下HOME鍵後,由于系統不知道使用者會新開多少程式,因而這個Activity可能會由于系統資源不足而被系統kill,因為在onPause之後會調用onSaveInstance來儲存資料。

2、長按HOME鍵,選擇運作其他的程式時。分析同上。

3、按下電源按鍵(關閉螢幕顯示)時。分析同上。

4、從activity A中啟動一個新的activity時。分析同上。

5、螢幕方向切換時,例如從豎屏切換到橫屏時。在螢幕切換之前,系統會銷毀activity A,在螢幕切換之後系統又會自動地建立activity A,是以onSaveInstanceState一定會被執行。

一般調用方式如下:

一般系統殺死程序的順序是:

  Android系統會盡力保持應用的程序,但是有時為了給新的程序和更重要的程序回收一些記憶體空間,它會移除一些舊的程序。

  為了決定哪些程序留下,哪些程序被殺死,系統根據在程序中在運作的元件及元件的狀态,為每一個程序配置設定了一個優先級等級。

  優先級最低的程序首先被殺死。

  這個程序重要性的層次結構有五個等級,下面就列出這五種程序,按照重要性來排列,最重要的放在最前。 

  前台程序是使用者目前做的事所必須的程序,如果滿足下面各種情況中的一種,一個程序被認為是在前台:

  1.程序持有一個正在與使用者互動的Activity(Activity正處于onResume()的狀态)。

  2.程序持有一個Service,這個Service和使用者正在互動的Activity綁定。

  殺死前台程序需要使用者互動,因為前台程序的優先級是最高的。 

  如果一個程序不含有任何前台的元件,但是仍然影響着使用者在螢幕上可以看到的内容,就是可見程序。

  可見程序滿足下列情況之一:

  1.程序持有一個Activity,這個Activity不在前台,但是仍然被使用者可見(處于onPause()調用後又沒有調用onStop()的狀态)。

  這種情況發生在,比如,前台的activity打開了一個對話框,這樣activity就會在其後可見。

  2.程序持有一個Service,這個Service和一個可見的(或者前台的)Activity綁定。

  可見的程序也被認為是很重要的,一般不會被銷毀,除非是為了保證所有前台程序的運作而不得不殺死可見程序的時候。 

  盡管服務程序沒有和使用者可以看到的東西綁定,但是它們一般在做的事情是使用者關心的,比如背景播放音樂,背景下載下傳資料等。 

  如果程序不屬于上面三種情況,但是程序持有一個使用者不可見的activity(activity的onStop()被調用,但是onDestroy()沒有調用的狀态),就認為程序是一個背景程序。

  背景程序不直接影響使用者體驗,系統會為了前台程序、可見程序、服務程序而任意殺死背景程序。

  通常會有很多個背景程序存在,它們會被儲存在一個LRU (least recently used)清單中,這樣就可以確定使用者最近使用的activity最後被銷毀,即最先銷毀時間最遠的activity。 

  如果一個程序不包含任何活躍的應用元件,則認為是空程序。

  儲存這種程序的唯一理由是為了緩存的需要,為了加快下次要啟動這個程序中的元件時的啟動時間。

  系統為了平衡程序緩存和底層核心緩存的資源,經常會殺死空程序。 

  1.Android會盡可能地把程序放在高的優先級。

  比如,一個程序擁有一個可見狀态的activity和一個service,這個程序會被認為是可見程序,而不是服務程序。

  2.一個程序的等級有可能會因為其他程序的依賴而提高,一個程序服務于另一個程序,則它的優先級不會比它服務的程序優先級低。

  比如,A程序中的一個content provider向B程序中的一個客戶提供服務,或A程序中的一個service被綁定在B程序中的一個元件上,則A程序的優先級至少和B程序的優先級一樣高。

  3.因為服務程序的優先級比背景程序的優先級高,是以對于一個需要啟動一個長時間操作的activity來說,開啟一個service比建立一個工作線程的方法更好,尤其是對于操作将很可能超出activity的持續時間時。

  比如要上傳一個圖檔檔案,應該開啟一個service來進行上傳工作,這樣在使用者離開activity時工作仍在進行。使用service将會保證操作至少有服務程序的優先級。

總而言之,onSaveInstanceState的調用遵循一個重要原則,即當系統“未經你許可”時銷毀了你的activity,則onSaveInstanceState會被系統調用,這是系統的責任,因為它必須要提供一個機會讓你儲存你的資料。

onSaveInstanceState的調用是在onPause()之後執行的,即:onPause()—>onSaveInstanceState()–>onStop( );

至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成對的被調用的,onRestoreInstanceState被調用的前提是,activity A“确實”被系統銷毀了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會被調用,例如,當正在顯示activity A的時候,使用者按下HOME鍵回到主界面,然後使用者緊接着又傳回到activity A,這種情況下activity A一般不會因為記憶體的原因被系統銷毀,故activity A的onRestoreInstanceState方法不會被執行。同時onRestoreInstanceState的bundle參數也會傳遞到onCreate方法中,你也可以選擇在onCreate方法中做資料還原。

onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之間調用。

最後要說明下,在新版的SDK中,也就是API大于21的版本中新增了如下兩個函數:

這兩個函數主要是為了系統重新開機後的資料恢複,使用時需要在AndroidManifest.xml裡面的activity中添加android:persistableMode="persistAcrossReboots"屬性。PersistableBundle和Bundle差不多,是以key-value的形式使用的。具體代碼見如下工程。

繼續閱讀