本文介紹Android中關於Activity的兩個神祕方法:onSaveInstanceState和onRestoreInstanceState。前端
關於這兩個方法,一些朋友可能在Android開發不多用到,但在有時候掌握其用法會幫咱們起到比較好的效果。android
1. 基本做用簡介:數據庫
Activity的 onSaveInstanceState() 和 onRestoreInstanceState()並非生命週期方法,它們不一樣於 onCreate()、onPause()等生命週期方法,它們並不必定會被觸發。當應用遇到意外狀況(如:內存不足、用戶直接按Home鍵)由系統銷燬一個Activity時,onSaveInstanceState() 會被調用。可是當用戶主動去銷燬一個Activity時,例如在應用中按返回鍵,onSaveInstanceState()就不會被調用。由於在這種狀況下,用戶的行爲決定了不須要保存Activity的狀態。一般onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。緩存
在activity被殺掉以前調用保存每一個實例的狀態,以保證該狀態能夠在onCreate(Bundle)或者onRestoreInstanceState(Bundle) (傳入的Bundle參數是由onSaveInstanceState封裝好的)中恢復。這個方法在一個activity被殺死前調用,當該activity在未來某個時刻回來時能夠恢復其先前狀態。框架
例如,若是activity B啓用後位於activity A的前端,在某個時刻activity A由於系統回收資源的問題要被殺掉,A經過onSaveInstanceState將有機會保存其用戶界面狀態,使得未來用戶返回到activity A時能經過onCreate(Bundle)或者onRestoreInstanceState(Bundle)恢復界面的狀態。ide
2. onSaveInstanceState調用時機測試
先看Application Fundamentals上的一段話:spa
Android calls onSaveInstanceState() before the activitybecomes vulnerable to being destroyed by the system, but does not bothercalling it when the instance is actually being destroyed by a user action (suchas pressing the BACK key).線程
從這句話能夠知道,當某個activity變得「容易」被系統銷燬時,該activity的onSaveInstanceState就會被執行,除非該activity是被用戶主動銷燬的,例如當用戶按BACK鍵的時候。code
注意上面的雙引號,何爲「容易」?言下之意就是該activity尚未被銷燬,而僅僅是一種可能性。這種可能性有哪些?經過重寫一個activity的全部生命週期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,咱們能夠清楚地知道當某個activity(假定爲activity A)顯示在當前task的最上層時,其onSaveInstanceState方法會在何時被執行,有這麼幾種狀況:
A、當用戶按下HOME鍵時。
這是顯而易見的,系統不知道你按下HOME後要運行多少其餘的程序,天然也不知道activity A是否會被銷燬,故系統會調用onSaveInstanceState,讓用戶有機會保存某些非永久性的數據。如下幾種狀況的分析都遵循該原則
B、長按HOME鍵,選擇運行其餘的程序時。
C、按下電源按鍵(關閉屏幕顯示)時。
D、從activity A中啓動一個新的activity時。
E、屏幕方向切換時,例如從豎屏切換到橫屏時。
在屏幕切換以前,系統會銷燬activity A,在屏幕切換以後系統又會自動地建立activity A,因此onSaveInstanceState必定會被執行,且也必定會執行onRestoreInstanceState。
總而言之,onSaveInstanceState的調用遵循一個重要原則,即當系統存在「未經你許可」時銷燬了你的activity的可能時,則onSaveInstanceState會被系統調用,這是系統的責任,由於它必需要提供一個機會讓你保存你的數據(固然你不保存那就隨便你了)。若是調用,調用將發生在onPause()或onStop()方法以前。(雖然測試時發現多數在onPause()前)
3. onRestoreInstanceState調用時機
onRestoreInstanceState被調用的前提是,activity A「確實」被系統銷燬了,而若是僅僅是停留在有這種可能性的狀況下,則該方法不會被調用,例如,當正在顯示activity A的時候,用戶按下HOME鍵回到主界面,而後用戶緊接着又返回到activity A,這種狀況下activity A通常不會由於內存的緣由被系統銷燬,故activity A的onRestoreInstanceState方法不會被執行 此也說明上兩者,大多數狀況下不成對被使用。
4. onSaveInstanceState()方法的默認實現
若是開發者沒有覆寫onSaveInstanceState()方法, 此方法的默認實現會自動保存activity中的某些狀態數據, 好比activity中各類UI控件的狀態. android應用框架中定義的幾乎全部UI控件都恰當的實現了onSaveInstanceState()方法,所以當activity被摧毀和重建時, 這些UI控件會自動保存和恢復狀態數據. 好比EditText控件會自動保存和恢復輸入的數據,而CheckBox控件會自動保存和恢復選中狀態.開發者只須要爲這些控件指定一個惟一的ID(經過設置android:id屬性便可), 剩餘的事情就能夠自動完成了.若是沒有爲控件指定ID, 則這個控件就不會進行自動的數據保存和恢復操做.
由上所述, 若是開發者須要覆寫onSaveInstanceState()方法, 通常會在第一行代碼中調用該方法的默認實現:super.onSaveInstanceState(outState).
5. 是否須要覆寫onSaveInstanceState()方法
既然該方法的默認實現能夠自動的保存UI控件的狀態數據, 那何時須要覆寫該方法呢?
若是須要保存額外的數據時, 就須要覆寫onSaveInstanceState()方法。onSaveInstanceState()方法只適合保存瞬態數據, 好比UI控件的狀態, 成員變量的值等。 (見下例)。
因爲onSaveInstanceState()方法方法不必定會被調用, 所以不適合在該方法中保存持久化數據, 例如向數據庫中插入記錄等. 保存持久化數據的操做應該放在onPause()中。如果永久性值,則在onPause()中保存;若大量,則另開線程吧,別阻塞UI線程。
6. 引起activity摧毀和重建的其它情形
除了系統處於內存不足的緣由會摧毀activity以外, 某些系統設置的改變也會致使activity的摧毀和重建. 例如改變屏幕方向(見上例), 改變設備語言設定, 鍵盤彈出等。
另外,當屏幕的方向發生了改變, Activity會被摧毀而且被從新建立,若是你想在Activity被摧毀前緩存一些數據,而且在Activity被從新建立後恢復緩存的數據。能夠重寫Activity的 onSaveInstanceState() 和 onRestoreInstanceState()方法,以下:
7. 代碼示例以下所示:
public class MainActivity extends Activity { public static final int SECOND_ACTIVITY =0; private String temp; @Override public void onCreate(<span style="color:#ff6666;">BundlesavedInstanceState</span>) { super.onCreate(savedInstanceState); // 從savedInstanceState中恢復數據, 若是沒有數據須要恢復savedInstanceState爲null if (<span style="color:#ff6666;">savedInstanceState</span> != null) { temp =savedInstanceState.getString("temp"); System.out.println("onCreate:temp = " + temp); } } public void onResume() { super.onResume(); temp = "xing"; System.out.println("onResume:temp = " + temp); // 切換屏幕方向會致使activity的摧毀和重建 if (getRequestedOrientation() ==ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); System.out.println("屏幕切換"); } } // 將數據保存到outState對象中, 該對象會在重建activity時傳遞給onCreate方法 @Override protected void <span style="color:#ff0000;">onSaveInstanceState</span>(BundleoutState) { super.onSaveInstanceState(outState); outState.putString("temp",temp); } }
須要注意的是, onSaveInstanceState()方法並非必定會被調用的, 由於有些場景是不須要保存狀態數據的. 好比用戶按下BACK鍵退出activity時, 用戶顯然想要關閉這個activity, 此時是沒有必要保存數據以供下次恢復的, 也就是onSaveInstanceState()方法不會被調用. 若是調用onSaveInstanceState()方法,調用將發生在onPause()或onStop()方法以前.
@Overridepublic void onSaveInstanceState(BundlesavedInstanceState) { savedInstanceState.putBoolean("MyBoolean", true); savedInstanceState.putDouble("myDouble", 1.9); // etc. super.onSaveInstanceState(savedInstanceState); } @Overridepublic void onRestoreInstanceState(BundlesavedInstanceState) { super.onRestoreInstanceState(savedInstanceState); boolean myBoolean =savedInstanceState.getBoolean("MyBoolean"); double myDouble =savedInstanceState.getDouble("myDouble"); }