Android學習札記35:onSaveInstanceState (Bundle outState)方法

PART 1:


首先看下官方文檔的解釋:



稍微翻一下:


在 Activity 被銷燬之前被調用來保存每個實例的狀態,這樣就可以保證該狀態能夠從 onCreate(Bundle) 或者onRestoreInstanceState(Bundle)恢復過來。


本方法在 Activity 可能被銷燬前調用,這樣當該 Activity 在將來某個時刻重新回來時可以恢復其之前的狀態。例如,如果 Activity B 啓用後位於 Activity A 的前端,在某個時刻 Activity A 因爲系統回收資源的原因要被銷燬,Activity A 有機會通過 onSaveInstanceState() 來保存其用戶界面狀態,使得將來用戶返回到 Activity A 的時候能夠通過 onCreate(Bundle) 或者onRestoreInstanceState(Bundle) 來恢復其界面狀態。


不要將這個方法和 Activity 生命週期中的回調如 onPause() 或 onStop() 搞混淆了,onPause() 在 Activtiy 被放置到後臺或者自行銷燬時總會被調用,onStop() 在 Activity 被銷燬時被調用。一個會調用 onPause() 和 onStop() 但不會觸發 onSaveInstanceState() 的例子是當用戶從 Activity B 返回到 Activity A 時:沒有必要調用 B 的 onSaveInstanceState(Bundle)方法,因爲此時的 B 實例永遠不會被恢復,因此係統會避免調用它。一個調用 onPause() 但不調用 onSaveInstanceState(Bundle) 方法的例子是當 Activity B 啓動後處在 Activity A 的前端:如果在B的整個生命週期裏 A 的用戶界面狀態都沒有被破壞的話,系統是不會調用 Activity A 的onSaveInstanceState(Bundle)方法。


默認的實現負責了大部分 UI 實例狀態的保存,採用的方式是調用 UI 層上每個擁有 id 的 view 的 onSaveInstanceState()方法 ,並且保存當前獲得焦點的 view 的 id (所有保存的狀態信息都會在默認的 onRestoreInstanceState(Bundle) 實現中恢復)。如果你覆寫這個方法來保存額外的沒有被各個view保存的信息,你可能想要在默認實現過程中調用或者自己保存每個視圖的所有狀態。


如果被調用,這個方法會在 onStop() 前被觸發,但系統並不保證是否在 onPause() 之前或者之後觸發。



PART 2:


Activity 中的 onSaveInstanceState() 方法和 onRestoreInstanceState() 方法並不是生命週期方法,它們不同於 onCreate()、onPause() 等生命週期方法,它們並不一定會被觸發。當應用遇到意外情況(如:內存不足、用戶直接按Home鍵),由系統銷燬一個 Activity 時,onSaveInstanceState() 方法就會被調用。但是當用戶主動去銷燬一個 Activity 時,例如在應用中按返回鍵,onSaveInstanceState() 方法就不會被調用。因爲在這種情況下,用戶的行爲決定了不需要保存Activity的狀態。通常onSaveInstanceState() 方法只適合用於保存一些臨時性的狀態,而onPause() 方法適合用於數據的持久化保存。


另外,當屏幕的方向發生了改變, Activity 會被銷燬並重新創建,如果你想在 Activity 被銷燬前緩存一些數據,並且在 Activity 被重新創建後恢復緩存的數據。可以重寫 Activity 中的 onSaveInstanceState() 方法和 onRestoreInstanceState()方法,如下: 

public class PreferencesActivity extends Activity {
	
	private String name;

	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		// 重新創建後恢復緩存的數據
		name = savedInstanceState.getString("name");
		super.onRestoreInstanceState(savedInstanceState);
	}

	protected void onSaveInstanceState(Bundle outState) {
		// 被銷燬前緩存一些數據
		outState.putString("name", "l_yqing");
		super.onSaveInstanceState(outState);
	}
}


PART 3:


當用戶啓動一個新 Activity 之後,之前的 Activity 可能在內存中處於停止狀態也可能由於新 Activity 需要更多內存而被系統銷燬了,但不論怎樣,當用戶在新 Activity 上點擊返回鍵時,他希望看到的是原先的 Activity 的界面。原先的 Activity 如果是被重新創建的,那麼它就要恢復到用戶最後看到它時的樣子,我們該怎麼做呢?其實也不難,在 onPause() 、onStop() 或 onDestroy() 中保存必要的數據就行了。但是現在Google又冒出一個新的東西:onSaveInstanceState(),觀其名可知其意:它是專門用來保存實例狀態的,這個“實例”不是指的 Activity 對象,而是它所在的進程,因爲Activity 的銷燬是因爲它所在的進程被殺掉而造成的。onSaveInstanceState()是在系統感覺需要銷燬Activity時調用的,它被傳入一個參數Bundle,這個Bundle可以被認爲是個 Map 字典之類的東西,用“鍵-值”的形式來保存數據。


現在又叫人蛋疼了:不是可以在 onPause() 中保存數據嗎?爲什麼又搞出這樣一個傢伙來?它們之間是什麼關係呢?
原來,onSaveInstanceState() 方法的主要目的是保存和 Activity 的狀態有關的數據,當系統在銷燬 Activity 時,如果它希望 Activity 下次出現的樣子跟之前完全一樣,那麼它就會調用onSaveInstanceState(),否則就不調用。所以要明白這一點:onSaveInstanceState() 方法並不是永遠都會調用。比如,當用戶在一個 Activity 點擊返回鍵時,就不會調用,因爲用戶此時明確知道這個 Activity 是要被銷燬的,並不期望下次它的樣子跟現在一樣(當然開發者可以使它保持臨死時的表情,你非要這樣做,系統也沒辦法),所以就不用調用onSaveInstanceState()。現在應該明白了:在onPause()、onStop() 以及 onDestroy() 中需要保存的是那些需要永久化的數據,而不是保存用於恢復狀態的數據,狀態數據有專門的方法:onSaveInstanceState()。數據保存在一個 Bundle 中,Bundle 被系統永久化。當再調用 Activity 的onCreate()時,原先保存的 Bundle就被傳入,以恢復上一次臨死時的模樣,如果上次被銷燬時沒有保存 Bundle,則爲 null。


還沒完呢,如果你沒有實現自己的 onSaveInstanceState(),但是 Activity 上控件的樣子可能依然能被保存並恢復。原來 Activity 類已實現了onSaveInstanceState(),在 onSaveInstanceState() 的默認實現中,會調用所有控件的相關方法,把控件們的狀態都保存下來,比如 EditText 中輸入的文字、CheckBox 是否被選中等等。然而不是所有的控件都能被保存,這取決於你是否在 layout 文件中爲控件賦了一個名字(android:id)。有名的就存,無名的不管。


既然有現成的可用,那麼我們到底還要不要自己實現 onSaveInstanceState() 方法呢?這就得看情況了,如果你自己的派生類中有變量影響到UI,或你程序的行爲,當然就要把這個變量也保存了,那麼就需要自己實現,否則就不需要,但大多數情況肯定需要自己實現一下下了。對了,別忘了在你的實現中調用父類的 onSaveInstanceState() 方法。

注:由於 onSaveInstanceState() 方法並不是在每次被銷燬時都會調用,所以不要在其中保存那些需要永久化的數據,執行保存那些數據的最好地方是在 onPause() 方法中。



參考資料:

http://blog.csdn.net/qjbagu/article/details/6743076

http://www.apkbus.com/forum.php?mod=viewthread&tid=13470&fromuid=3402

http://my.oschina.net/keeponmoving/blog/62107











發佈了42 篇原創文章 · 獲贊 5 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章