savedInstanceState和 fragment.setRetainInstance以及 viewmodel的區別

以默認activity的配置 在屏幕旋轉的時候,通常activty都會被重建,以這個狀況爲例子來講明 Bundle savedInstanceState 和 fragment.setRetainInstance 以及 viewmodel的區別c++

0. 轉載請註明原文出處

做者github :github.com/zjw-swun 歡迎相互關注git

1. 爲何要把這3個放在一塊說

Bundle savedInstanceState 和 fragment.setRetainInstance 以及 viewmodel(viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);用法而不是本身new的那種),都具有一種功能,就是當 屏幕旋轉的時候( 以默認activity的配置前提),都能保存一些要被銷燬掉的activity中的一些數據(如editext文本,以及recyclerView的滑動位置等),那麼這3個有什麼區別嗎,會不會由於咱們不知道原理而踩坑,下文給出答案。github

2. 結論

  1. 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 廢話很少說 放圖api

斷點列表

而後看重建activity時候的斷點(截圖中截的是被殺死的activity 走到ondestroy的時候)bash

圖片2
這裏說明一下上一個activty先走ondrstroy 而後才重建新的activity這裏和activity跳轉作一個區分,而後從上圖中能夠發現被殺死的activity 走到ondestroy的時候中的 r和重建時候傳入的參數 r(ActivityThread類中的ActivityClientRecord類型)是同一個對象,看看一下這個ActivityClientRecord類的代碼

static final class ActivityClientRecord {
       //...不重要參數
        Activity.NonConfigurationInstances lastNonConfigurationInstances;
        //...不重要參數;
        }
複製代碼

這就是核心的原理代碼了,那麼爲何說是存儲在app進程中呢,根據斷點列表你會發現涉及到一個關鍵類叫作 ActivityRelaunchItem這個類 app

圖片描述
這個類的 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存下來的 rlastNonConfigurationInstances再設置給新activity

中間省略的步驟雖然多,可是根據斷點列表走下來其實很清楚的。ide

授人以魚不如授人以漁

對於如何調試app進程和系統進程,www.imooc.com/article/219… 一文中有具體操做,可是涉及到binder類是如何進行transact發消息給別的進程以及如何execTransact處理別的進程消息 的c++層的原理並無給出解答,這裏推薦一篇博客 blog.csdn.net/innost/arti… 講解的還算不錯。函數

相關文章
相關標籤/搜索