以預設activity的配置 在螢幕旋轉的時候,一般activty都會被重建,以這個情況為例子來說明 Bundle savedInstanceState 和 fragment.setRetainInstance 以及 viewmodel的區別
0. 轉載請註明原文出處
作者github :github.com/zjw-swun 歡迎相互關注
1. 為什麼要把這3個放在一塊說
Bundle savedInstanceState 和 fragment.setRetainInstance 以及 viewmodel(viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);用法而不是自己new的那種),都具備一種功能,就是當 螢幕旋轉的時候( 以預設activity的配置前提),都能儲存一些要被銷燬掉的activity中的一些資料(如editext文字,以及recyclerView的滑動位置等),那麼這3個有什麼區別嗎,會不會因為我們不知道原理而踩坑,下文給出答案。
2. 結論
Bundle savedInstanceState
中的資料是由系統程式進行儲存的,它能儲存的資料容量大小有限
(例如intent中如果傳輸Bundle內容過大會出現異常),但是比如自己app因為手機記憶體不足而殺掉程式的話,可以能夠
利用該方式進行資料還原 2.fragment.setRetainInstance
以及viewmodel
(viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);用法而不是自己new的那種)的原理是一樣的,都是利用,Activity類的NonConfigurationInstances
類在app程式中進行儲存的,它能儲存資料容量比Bundler savedInstanceState 方式要大
,但是比如自己app因為手機記憶體不足而殺掉程式的話,則不能
用該方式進行資料還原
3. 部分原始碼分析
以下以activity類中NonConfigurationInstances類如何在螢幕旋轉的時候( 以預設activity的配置前提)如何儲存並恢復NonConfigurationInstances物件為例,剖析原理
以下截圖以及截圖中的程式碼api版本為28,執行環境官方api 28的模擬器上
測試程式碼就不貼了很簡單, 先貼一下debug斷點列表,有興趣可以試試,至於如何debug app以及debug系統程式,不知道的朋友可以看一下我另一篇文章https://www.imooc.com/article/21992
廢話不多說 放圖
然後看重建activity時候的斷點(截圖中截的是被殺死的activity 走到ondestroy的時候)
這裡說明一下上一個activty先走ondrstroy 然後才重建新的activity這裡和activity跳轉做一個區分,然後從上圖中可以發現被殺死的activity 走到ondestroy的時候中的r
和重建時候傳入的引數r
(ActivityThread類中的ActivityClientRecord型別)是同一個物件,看看一下這個ActivityClientRecord類的程式碼
static final class ActivityClientRecord {
//...不重要引數
Activity.NonConfigurationInstances lastNonConfigurationInstances;
//...不重要引數;
}
複製程式碼
這就是核心的原理程式碼了,那麼為什麼說是儲存在app程式中呢,根據斷點列表你會發現涉及到一個關鍵類叫做
ActivityRelaunchItem
這個類
mActivityClientRecord
就是app程式儲存的那個r
了,這個r
裡面包含了lastNonConfigurationInstances
,當activty切換的時候,系統程式通過binder機制通知app程式的client物件也就是activityThread間接呼叫preExecute
方法,進行儲存,然後當重建activity的時候再系統程式通過binder機制通知app程式的client物件也就是activityThread(由activityThread.h傳送H.RELAUNCH_ACTIVITY
訊息通過handler機制)間接呼叫execute
方法
下圖是activity重建時候呼叫execute
函式呼叫棧截圖
重建activty後進行attach把上個被殺死的activity存下來的r
中lastNonConfigurationInstances
再設定給新activity
中間省略的步驟雖然多,但是根據斷點列表走下來其實很清楚的。
授人以魚不如授人以漁
對於如何除錯app程式和系統程式,www.imooc.com/article/219… 一文中有具體操作,但是涉及到binder
類是如何進行transact
發訊息給別的程式以及如何execTransact
處理別的程式訊息 的c++層的原理並沒有給出解答,這裡推薦一篇部落格 blog.csdn.net/innost/arti… 講解的還算不錯。