ViewModel的原理

眾所周知,ViewModel的作用在于以可感知生命周期的方式存儲與管理UI相關的數(shù)據(jù),它允許數(shù)據(jù)在例如屏幕旋轉這樣的配置發(fā)生變化時得以保存,那系統(tǒng)又是如何做到保存ViewModel的呢,讓我們從源碼中去溯本追源吧。

AndroidX支持庫中的AppCompatActivity繼承自FragmentActivity,而后者又繼承自ComponentActivity,ComponentAcitivty實現(xiàn)了ViewModelStoreOwner接口,該接口定義如下:
屏幕快照 2020-05-22 下午8.52.32.png

很顯然,實現(xiàn)該接口的類需要能夠提供一個ViewModelStore,而ViewModelStore即為用于存儲ViewModel對象的倉庫,其內(nèi)部通過一個HashMap管理ViewModel。

當需要獲取ViewModel時,需先創(chuàng)建ViewModelProvider實例,在2.2.0版本的ViewModel庫中,不再通過ViewModelProvider的靜態(tài)of方法獲取實例,而需要通過ViewModelProvider的構造函數(shù)去創(chuàng)建實例,其存在如下構造函數(shù):
屏幕快照 2020-05-24 下午10.27.15.png

在這個構造函數(shù)內(nèi),會通過ViewModelStoreOwner的getViewModelStore方法獲取到ViewModelStore,而ViewModelProvider的get方法則使用該ViewModelStore去獲取ViewModel,其獲取邏輯如下:
屏幕快照 2020-05-24 下午9.08.55.png
從代碼中可看出,如果ViewModel已經(jīng)在ViewModelStore中存在,則直接從中獲取,否則會創(chuàng)建ViewModel并存入ViewModelStore中。因為AppCompatActivity實現(xiàn)了ViewModelStoreOwner接口,所以我們可以傳入AppCompatActivity對象獲取到ViewModelProvider實例,進而獲取ViewModel對象。

接下來看下ComponentActivity對ViewModelStoreOwner接口的實現(xiàn):
屏幕快照 2020-05-22 下午8.57.54.png

在方法內(nèi)部會先判斷當前是否已經(jīng)存在ViewModelStore,如果不存在則先獲取NonConfiguratioInstances并從其中取出ViewModelStore,否則創(chuàng)建一個ViewModelStore。獲取NonConfigurationInstances實例的代碼如下:
屏幕快照 2020-05-24 下午10.20.41.png
所以這里的NonConfigurationInstances就是系統(tǒng)保存ViewModel的關鍵所在。
那么這個NonConfigurationInstances又是從何而來的呢,通過方法跟蹤,可找到其在Activity的attach方法中通過方法參數(shù)傳入
@UnsupportedAppUsage
final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
              ……
          mLastNonConfigurationInstances = lastNonConfigurationInstances;
              ……
}

Activity的attach方法是在Activity的加載流程中由ActivityThread的performLaunchActivity調(diào)用的,調(diào)用時傳入的是ActivityRecordClient中的NonConfigurationInstances對象,那ActivityRecordClient又是在什么時候保存的NonConfigurationInstances對象的呢,這就要從Activity因為配置變化被銷毀時查起了。

當Activity因為配置變化被銷毀時,在其銷毀流程中ActivityThread會調(diào)用performDestroyActivity方法,該方法內(nèi)部會回調(diào)Activity的retainNonConfigurationInstances方法獲取NonConfigurationInstances并保存在ActivityRecordClient中以備之后Activity重建之需,以下是retainNonConfigurationInstances方法的部分流程:

NonConfigurationInstances retainNonConfigurationInstances() {
        Object activity = onRetainNonConfigurationInstance();
        ……
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.activity = activity;
        ……
        return nci;
}

其中onRetainNonConfigurationInstance()方法由ComponentActivity進行了覆寫:
屏幕快照 2020-05-24 下午10.04.02.png

onRetainNonConfigurationInstances方法的主要邏輯就是創(chuàng)建了一個NonConfigurationInstances對象(此NonConfigurationInstances類與前頭的NonConfigurationInstances類不是同一個類),并將當前Activity的ViewModelStore保存到了所創(chuàng)建的對象的viewModelStore變量中,從而使得Activity在銷毀后重建時能獲取到銷毀前的ViewModelStore,進而可獲取到銷毀前的ViewModel。onRetainNoConfigurationInstance方法返回的NonConfigurationInstance對象最終被存儲到了retainNonConfigurationInstances方法中創(chuàng)建的NonConfigurationInstances對象的activity變量里。

需要注意的是,如果Activity是正常的銷毀,那么ViewModelStore會清空其保存的所有ViewModel,而如果是因為配置變化而被銷毀,則不清空,這個邏輯可由ComponentActivity的構造函數(shù)中覓得:
屏幕快照 2020-05-22 下午10.05.53.png
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容