onSaveInstanceState和onRestoreInstanceState詳解
路過的坑總結下才不會又踏進去 mark下
一. 作用
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() 和 onRestoreInstanceState() 兩個函式的基本作用和用法。(ps:關於原理實現請追尋原始碼,就是view的儲存與繪製)
二. onSaveInstanceState的呼叫時機
當某個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()前)
**三. onRestoreInstanceState()呼叫時機 **
onRestoreInstanceState()被呼叫的前提是,activity A“確實”被系統銷燬了,而如果僅僅是停留在有這種可能性的情況下,則該方法不會被呼叫,例如,當正在顯示activity A的時候,使用者按下HOME鍵回到主介面,然後使用者緊接著又返回到activity A,這種情況下activity A一般不會因為記憶體的原因被系統銷燬,故activity A的onRestoreInstanceState方法不會被執行 此也說明上二者,大多數情況下不成對被使用。
onRestoreInstanceState()在onStart() 和 onPostCreate(Bundle)之間呼叫。
四. onSaveInstanceState()方法的預設實現
如果我們沒有覆寫onSaveInstanceState()方法, 此方法的預設實現會自動儲存activity中的某些狀態資料, 比如activity中各種UI控制元件的狀態.。android應用框架中定義的幾乎所有UI控制元件都恰當的實現了onSaveInstanceState()方法,因此當activity被摧毀和重建時, 這些UI控制元件會自動儲存和恢復狀態資料. 比如EditText控制元件會自動儲存和恢復輸入的資料,而CheckBox控制元件會自動儲存和恢復選中狀態.開發者只需要為這些控制元件指定一個唯一的ID(通過設定android:id屬性即可), 剩餘的事情就可以自動完成了.如果沒有為控制元件指定ID, 則這個控制元件就不會進行自動的資料儲存和恢復操作。
由上所述, 如果我們需要覆寫onSaveInstanceState()方法, 一般會在第一行程式碼中呼叫該方法的預設實現:super.onSaveInstanceState(outState)。
**五. 是否需要重寫onSaveInstanceState()方法 **
既然該方法的預設實現可以自動的儲存UI控制元件的狀態資料, 那什麼時候需要覆寫該方法呢?
如果需要儲存額外的資料時, 就需要覆寫onSaveInstanceState()方法。大家需要注意的是:onSaveInstanceState()方法只適合儲存瞬態資料, 比如UI控制元件的狀態, 成員變數的值等,而不應該用來儲存持久化資料,持久化資料應該當使用者離開當前的 activity時,在 onPause() 中儲存(比如將資料儲存到資料庫或檔案中)。說到這裡,還要說一點的就是在onPause()中不適合用來儲存比較費時的資料,所以這點要理解。
由於onSaveInstanceState()方法方法不一定會被呼叫, 因此不適合在該方法中儲存持久化資料, 例如向資料庫中插入記錄等. 儲存持久化資料的操作應該放在onPause()中。若是永久性值,則在onPause()中儲存;若大量,則另開執行緒吧,別阻塞UI執行緒。
六. 引發activity銷燬和重建的其它情況
除了系統處於記憶體不足的原因會摧毀activity之外, 某些系統設定的改變也會導致activity的摧毀和重建. 例如改變螢幕方向(見上例), 改變裝置語言設定, 鍵盤彈出等。
Android歷練記 是一個關於Android最新技術探討,包含安全,架構,Android技術開發,ui繪製,原始碼解析等領域,如果你有興趣,我們可以一起討論學習,
關注微信公眾號 Android歷練記 或掃一掃二維碼:
相關文章
- Android onSaveInstanceState()、onRestoreInstanceState()儲存和恢復被系統銷燬的資料AndroidREST
- startActivityForResult()和onSaveInstanceState()用法
- 解決IllegalStateException: Can not perform this action after onSaveInstanceStateExceptionORM
- Activity onSaveInstanceState(Bundle)
- ViewModel:持久化、onSaveInstanceState()、UI 狀態恢復和 LoaderView持久化UI
- DR和BDR詳解
- 詳解 let 和 var
- require 和 import 詳解UIImport
- exp和imp詳解
- 詳解jdbcTemplate和namedParameterJdbcTemplateJDBC
- xargs 和 exec詳解
- jni和ndk詳解
- ckeckpoint和SCN詳解
- startActivityForResult和setResult詳解
- ROP漏洞詳解和利用
- WebRTC SDP 詳解和剖析Web
- pandas qcut 和cut 詳解
- [譯]KVC 和 KVO詳解
- cookie和session的詳解CookieSession
- HTTP和HTTPS詳解HTTP
- iOS KVC和KVO詳解iOS
- rowspan和colspan用法詳解
- HTTP和HTTPS詳解。HTTP
- IP校驗和詳解
- RabbitMQ的詳解和使用MQ
- android WebView詳解,常見漏洞詳解和安全原始碼AndroidWebView原始碼
- Vue $dispatch 和 $broadcast 詳解VueAST
- crontab和cron表示式詳解
- Git詳解和Github的使用Github
- Promise和async await詳解PromiseAI
- javascript原型和原型鏈詳解JavaScript原型
- Java PATH和CLASSPATH配置詳解Java
- Blocks深入理解和詳解BloC
- jQuery offset()和position()用法詳解jQuery
- URIEncoding和useBodyEncodingForURI詳解Encoding
- Get和Post請求詳解
- oracle pctfree和pctused詳解Oracle
- oracle中not in和not exsist詳解Oracle