Android ViewModel源碼分析
本文將分成以下幾個部分:
ViewModel如何被構(gòu)建出來?
ViewModel為什么能存儲數(shù)據(jù)?

PART 1 ViewModel的構(gòu)建流程
我們通??梢允褂胋y viewModels()的方式構(gòu)建ViewModel的實例,viewModels()作為ComponentActivity的擴展函數(shù),會返回一個ViewModelLazy。
ViewModelStore和ViewModelFactory
這里需要注意一下,傳入的viewModelStore和defaultViewModelProviderFactory都是ComponentActivity的屬性。
ViewModelStore基于HashMap的結(jié)構(gòu)進行ViewModel的存儲:
當ComponentActivity被銷毀時清除其中的數(shù)據(jù):
Factory默認使用的是SavedStateViewModelFactory,具體的構(gòu)建過程下面會說到。
說回剛才的ViewModelLazy,Lazy作為一個懶加載的通用接口,其中的value屬性表示在Lazy對象的生命周期過程中只能被修改一次的屬性。所以具體看看ViewModelLazy對于value的get方法的重寫:
首先是調(diào)用ViewModelProvider的構(gòu)造函數(shù),然后調(diào)用get方法:
在后面的get方法中可以看到,如果ViewModelStore中的map存在緩存,我們直接從緩存中找到ViewModel,否則調(diào)用KeyedFactory#create,SavedStateViewModelFactory就是一個KeyedFactory的子類。
create方法中通過構(gòu)建SavedStateHandleController,然后向ViewModel中塞入了一個SavedStateHandle,從而構(gòu)建了ViewModel。SavedStateHandle就是ViewModel能夠進行狀態(tài)保存的關(guān)鍵所在,這里先賣個關(guān)子,最后一節(jié)會詳細解釋。
至此,我們已經(jīng)稍微涉及到了ViewModel狀態(tài)保存的關(guān)鍵角色,這些關(guān)鍵角色在后面的調(diào)用鏈中我使用不同顏色的方塊表示:

以上的ViewModel的構(gòu)建部分已經(jīng)介紹完畢,總結(jié)如下圖:

ViewModel創(chuàng)建過程總結(jié):
ViewModel創(chuàng)建過程在Kotlin中基于by 語法,但是本質(zhì)上還是通過ViewModelProvider創(chuàng)建,所以我們在Java中調(diào)用的是ViewModelProvider的方法。
ViewModelProvider創(chuàng)建ViewModel的奧秘在于ComponentActivity中的兩個關(guān)鍵角色,ViewModelStore和SavedStateViewModelFactory。如果存在ViewModel的緩存,ViewModelStore會取出,如果沒有緩存,通過Factory構(gòu)建。
Factory構(gòu)建時放入了SavedStateHandle,它是ViewModel可以進行狀態(tài)保存的奧秘所在。
下面進入PART2,詳細講述SavedState這些兄弟是如何工作的。

PART2:ViewModel如何保存狀態(tài)
我們先由上至下閱讀,先從頂部的結(jié)構(gòu)一直到底部,最后再對涉及到的角色進行一個總結(jié)
SavedStateRegistryController
在ComponentActivity中會調(diào)用Controller的performRestore和performSave方法:
具體看看實現(xiàn):
這些Controller可以說是SavedStateRegistry的外觀,它持有LifecycleOwner和Registry的實例:
并且具體的操作也依托著Registry的
同名方法。下面我們看看Registry中的perform方法的實現(xiàn)
SavedStateRegistry
看看其中的兩個perform方法:
performRestore的邏輯還算簡單,就是將Key所對應(yīng)的內(nèi)容讀取到mRestoredState這個Bundle中。performSave的邏輯總結(jié)而言就是將Map中的SavedStateProvider和mRestoreState都存在了mBundle中。我們在SavedStateHandle中還會見到SavedStateProvider發(fā)揮它的作用,所以說到的時候再具體說。

所以這塊的邏輯是這樣,當onCreate調(diào)用時,會執(zhí)行performRestore,將Bundle中的數(shù)據(jù)寸在SavedStateRegistry的Bundle mRestoreState中;當執(zhí)行onSaveInstanceState時,會從Bundle mRestoreState中讀取數(shù)據(jù),具體怎么讀的,怎么使用的Bundle中的數(shù)據(jù)的,還記得SavedStateHandle嗎,就是存放在ViewModel中的那個,現(xiàn)在我們來看看:
SavedStateHandle
我們先回顧一下構(gòu)建ViewModel的邏輯時的圖:

在Factory的create方法的調(diào)用鏈上還調(diào)用了SavedStateHandleController#attachToLifecycle方法:
這個方法除了做了生命周期的操作之外,還將Provider注冊到了SaveStateRegistry中。我們現(xiàn)在來看SavedStateHandle中的Provider的實現(xiàn):

所以返回的Bundle中是一個ArrayList<String>和ArrayList<Object>的結(jié)構(gòu)。
這里其實我沒分析特別明白,我不知道這部分的Provider綁定到ViewModel之后如何取出數(shù)據(jù)的,而且官方文檔中也沒說清楚。

我們看看官方給出的使用ViewModel保存狀態(tài)的例子中是如何使用到這些結(jié)構(gòu)的。
直接使用SavedStateHandle保存數(shù)據(jù)
數(shù)據(jù)在進程終止時會保存下來。SavedStateHandle會將結(jié)果存在mRegular中,如果Activity被銷毀,就回調(diào)用onSaveInstanceState->SavedStateRegistry#performSave->Provider#saveState獲取到對應(yīng)的數(shù)據(jù)。在SavedStateProvider#saveState是將鍵名和值,使用put方法放入Bundle。
通過寫SavedStateProvider
在官方的例子中,如果我們想要使用保存狀態(tài)的功能,分成以下幾步:
定義Provider
將Provider注冊到SavedStateRegistry
其實這個寫法和上面的相似,但是因為在創(chuàng)建ViewModel的時候,尤其是使用by viewModels時,會自動創(chuàng)建SavedStateHandle。我們在自定義的Provider中實現(xiàn)saveState方法,在onSaveInstanceState時,也會通過SavedStateRegistry#performSave調(diào)用。進而也會保存在Bundle中
總結(jié)
雖然寫了這么多,但是其實我個人其實對于ViewModel的狀態(tài)保存還不是特別理解。根據(jù)我個人的理解,SavedState相關(guān)的幾個類的關(guān)系如下:

ViewModel的創(chuàng)建通過ViewModelProvider實現(xiàn),主要通過ViewModelStore和Factory這樣兩個重要的角色。首先會從緩存中找是否存在ViewModel,如果沒有在調(diào)用SavedStateViewModelFactory#create構(gòu)建新的ViewModel。而且ViewModel的生命周期很長,通過Lifecycle回調(diào)進行監(jiān)聽,如果是onDestroy,就回調(diào)用ViewModel#onClear。
ViewModel實現(xiàn)狀態(tài)的保存有賴于SavedStateHandle及其內(nèi)部的SavedStateProvider實現(xiàn)。當Activity要被銷毀時,調(diào)用SavedStateRegistry#performSave就會調(diào)用系統(tǒng)默認注冊的SavedStateHandle中的Provider,保存數(shù)據(jù)。
用戶可以通過傳入SavedStateHandle(在Factory#create中反射調(diào)用了一個具有SaveStateHandle的構(gòu)造方法,這個方法在ViewModel中是沒有的)實現(xiàn)保存狀態(tài);也可以實現(xiàn)Provider,兩者的原理大體相同。
鑒于我對于狀態(tài)保存還理解不深入,之后遇到開發(fā)問題再過來補充!