標籤:
首先來介紹onSaveInstanceState() 和 onRestoreInstanceState() 。關於這兩個方法,一些朋友可能在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)恢複介面的狀態。
關於onSaveInstanceState (),是在函數裡面儲存一些View有用的資料到一個Parcelable對象並返回。在Activity的onSaveInstanceState(Bundle outState)中調用View的onSaveInstanceState (),返回Parcelable對象,
接著用Bundle的putParcelable方法儲存在Bundle savedInstanceState中。
當系統調用Activity的的onRestoreInstanceState(Bundle savedInstanceState)時, 同過Bundle的getParcelable方法得到Parcelable對象,然後把該Parcelable對象傳給View的onRestoreInstanceState (Parcelable state)。在的View的onRestoreInstanceState中從Parcelable讀取儲存的資料以便View使用。
這就是onSaveInstanceState() 和 onRestoreInstanceState() 兩個函數的基本作用和用法。
2. onSaveInstanceState() 什麼時候調用
先看Application Fundamentals上的一段話:
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鍵的時候。
注意上面的雙引號,何為"容易"?意思就是說該activity還沒有被銷毀,而僅僅是一種可能性。這種可能性有哪些?通過重寫一個activity的所有生命週期的onXXX方法,包括onSaveInstanceState()和onRestoreInstanceState() 方法,我們可以清楚地知道當某個activity(假定為activity A)顯示在當前task的最上層時,其onSaveInstanceState()方法會在什麼時候被執行,有這麼幾種情況:
(1)、當使用者按下HOME鍵時。
這是顯而易見的,系統不知道你按下HOME後要運行多少其他的程式,自然也不知道activity A是否會被銷毀,因此系統會調用onSaveInstanceState(),讓使用者有機會儲存某些非永久性的資料。以下幾種情況的分析都遵循該原則
(2)、長按HOME鍵,選擇運行其他的程式時。
(3)、按下電源按鍵(關閉螢幕顯示)時。
(4)、從activity A中啟動一個新的activity時。
(5)、螢幕方向切換時,例如從豎屏切換到橫屏時。
在螢幕切換之前,系統會銷毀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方法不會被執行 此也說明上二者,大多數情況下不成對被使用。
onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之間調用。
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控制項的狀態, 成員變數的值等,而不應該用來儲存持久化資料,持久化資料應該當使用者離開當前的 activity時,在 onPause() 中儲存(比如將資料儲存到資料庫或檔案中)。說到這裡,還要說一點的就是在onPause()中不適合用來儲存比較費時的資料,所以這點要理解。
由於onSaveInstanceState()方法方法不一定會被調用, 因此不適合在該方法中儲存持久化資料, 例如向資料庫中插入記錄等. 儲存持久化資料的操作應該放在onPause()中。若是永久性值,則在onPause()中儲存;若大量,則另開線程吧,別阻塞UI線程。
6. 引發activity銷毀和重建的其它情況
除了系統處於記憶體不足的原因會摧毀activity之外, 某些系統設定的改變也會導致activity的摧毀和重建. 例如改變螢幕方向(見上例), 改變裝置語言設定, 鍵盤彈出等。
另外,當螢幕的方向發生了改變, Activity會被摧毀並且被重新建立,如果你想在Activity被摧毀前緩衝一些資料,並且在Activity被重新建立後恢複緩衝的資料。可以重寫Activity的 onSaveInstanceState() 和 onRestoreInstanceState()方法。
下面來一個關於橫豎屏切換儲存資料的例子
[java] view plaincopy
- private VideoView videoView;
- private static final String VIDEO_PATH = Environment
- .getExternalStorageDirectory()
- + File.separator
- + "mymovie"
- + File.separator + "shenghuaweiji.mp4";
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Log.v("tag", "onCreate");
-
- if (videoView == null) {
- videoView = (VideoView) this.findViewById(R.id.myvideo);
- MediaController controller = new MediaController(this);
- videoView.setMediaController(controller);
- videoView.setVideoPath(VIDEO_PATH);
- videoView.requestFocus();
- }
-
- if (savedInstanceState != null
- && savedInstanceState.getInt("currentposition") != 0) {
-
- videoView.seekTo(savedInstanceState.getInt("currentposition"));
- }
- videoView.start();
-
- }
onCreate方法中的參數savedInstanceState就是儲存的Activity一些狀態。
savedInstanceState.getInt("currentposition") 擷取視頻播放時間。
[java] view plaincopy
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- // TODO Auto-generated method stub
- outState.putInt("currentposition", videoView.getCurrentPosition());
- Log.v("tag", "onSaveInstanceState");
- super.onSaveInstanceState(outState);
- }
重寫了onSaveInstanceState方法:將當前video的播放時間儲存在Bundle中。
這樣在橫豎屏切換時保證了播放狀態。
參考:http://blog.csdn.net/yuzhiboyi/article/details/7677026#
http://www.cnblogs.com/hanyonglu/archive/2012/03/28/2420515.html
Android onSaveInstanceState和onRestoreInstanceState()