本文主要內(nèi)容:
- 作用介紹
- 核心類介紹
- 基本使用
- 源碼分析
-- 橫豎屏切換恢復(fù)
-- 后臺銷毀恢復(fù)
ViewModel的主要工作:
本身主要是一個數(shù)據(jù)維護(hù)工具
將數(shù)據(jù)維護(hù)的工作從Activity
上剝離,提供一個儲存數(shù)據(jù)環(huán)境着绷,自身機(jī)制可以解決開發(fā)中址貌,數(shù)據(jù)受Activity
生命周期影響產(chǎn)生數(shù)據(jù)丟失的問題 (主要為橫豎屏切換以及在后臺被銷毀)窘面。
通常結(jié)合LiveData
使用。
作為一個純數(shù)據(jù)維護(hù)工具,可以加入到
MVP
架構(gòu)中負(fù)責(zé)數(shù)據(jù)保存。而官方推選作為
AAC
架構(gòu)MVVM
中的VM
層。
ViewModel的主要類:
ViewModel (下稱VM)
:
數(shù)據(jù)儲存類刃泡,架構(gòu)的核心類。
使用時碉怔,直接繼承該類烘贴,根據(jù)需求選擇重寫onCleared()
方法。
如需在Activity
被系統(tǒng)銷毀后依然保存數(shù)據(jù)撮胧,定義一個參數(shù)為(SavedStateHandle)
的構(gòu)造方法桨踪,并將數(shù)據(jù)保存SavedStateHandle
中。
實(shí)際上通過SavedInstanceState
存取AndroidViewModel
:
VM
子類趴樱,維護(hù)了Application
的引用馒闷,由架構(gòu)中的SavedStateViewModelFactory
創(chuàng)建時傳入。
同樣叁征,需要接收SavedStateHandle
時纳账,需要定義參數(shù)為(Application, SavedStateHandle)
的構(gòu)造方法。ViewModelStore
:
用于保存VM
捺疼,內(nèi)部維護(hù)了一個用于儲存VM
的HashMap
疏虫。
一般情況下,直接使用本類創(chuàng)建實(shí)例啤呼。ViewModelStoreOwner
:
接口卧秘,實(shí)現(xiàn)該接口的類,表示自身能夠向外提供VM
官扣。
androidx 的AppCompatActivity
/Fragment
實(shí)現(xiàn)了該接口翅敌。ViewModelProvider
:
VM
的提供者,獲取VM
的基本入口惕蹄。
實(shí)際依賴ViewModelStore
存取VM
蚯涮,Factory
生成/恢復(fù)VM
。Factory
:
接口卖陵,實(shí)現(xiàn)該接口的類主要用于創(chuàng)建VM
實(shí)例遭顶。
不建議直接實(shí)現(xiàn)該接口,除非你清楚框架內(nèi)容和自己的需求泪蔫。
一般情況下棒旗,如果無需SavedStateHandle
機(jī)制,可以使用AndroidViewModelFactory
撩荣。
否則應(yīng)該使用或繼承SavedStateViewModelFactory
铣揉。
ViewModel的基本使用:
- 一般使用:
// VM
class ViewModelA : ViewModel()
// AVM
class ViewModelB(app: Application) : AndroidViewModel(app)
// Activity/Fragment .onCreate中
override fun onCreate() {
...
val provider = ViewModelProvider(this)
val vmA = provider.get(ViewModelA::class.java)
val vmB = provider.get(ViewModelB::class.java)
...
}
- 接受 SavedStateHandle
// VM
class ViewModelC(
val handle: SavedStateHandle
) : ViewModel()
// AVM
class ViewModelD(
app: Application,
val handle: SavedStateHandle
) : AndroidViewModel(app)
-
跨 Fragment 共享數(shù)據(jù)
Fragment中直接以Activity作為ViewModel的Key
...
val provider = ViewModelProvider(requireActivity())
val vmA = provider.get(ViewModelA::class.java)
- 通過 Application 創(chuàng)建全局共享的 VM
class App : Application(), ViewModelStoreOwner {
private lateinit var mAppViewModelStore: ViewModelStore
private lateinit var mFactory: ViewModelProvider.Factory
override fun onCreate() {
super.onCreate()
mAppViewModelStore = ViewModelStore()
mFactory = ViewModelProvider
.AndroidViewModelFactory
.getInstance(this)
}
override fun getViewModelStore(): ViewModelStore {
return mAppViewModelStore
}
private fun getAppFactory(): ViewModelProvider.Factory {
return mFactory
}
fun getAppViewModelProvider(activity: Activity): ViewModelProvider {
val app = checkApplication(activity) as App
return ViewModelProvider(app, app.getAppFactory())
}
fun getAppViewModelProvider(fragment: Fragment): ViewModelProvider {
return getAppViewModelProvider(fragment.requireActivity())
}
private fun checkApplication(activity: Activity): Application {
return activity.application
?: throw IllegalStateException(
"Your activity is not yet attached to the Application instance." +
"You can't request ViewModel before onCreate call.")
}
}
ViewModel的關(guān)鍵源碼分析:
以下源碼分析將會去除非相關(guān)代碼以簡化
- ViewModelProvider 實(shí)現(xiàn)相關(guān):
前面提到饶深,ViewModelProvider
的工作完全依賴傳入的ViewModelStore
和Factory
,可以直接從構(gòu)造方法得知:
ViewModelProvider.java
----------------------
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
public ViewModelProvider(ViewModelStoreOwner owner) {
this(owner.getViewModelStore(),
owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner)
.getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(ViewModelStoreOwner owner, Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(ViewModelStore store, Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
// 簡單的反射創(chuàng)建實(shí)例的工廠
public static class NewInstanceFactory implements Factory {
public <T extends ViewModel> T create(Class<T> modelClass) {
return modelClass.newInstance()
}
}
而androidx.activity.ComponentActivity
逛拱,androidx.fragment.app.Fragment
都實(shí)現(xiàn)了ViewModelStoreOwner
粥喜,HasDefaultViewModelProviderFactory
接口。
public class AppCompatActivity extends FragmentActivity...{}
public class FragmentActivity extends ComponentActivity...{}
public class ComponentActivity extends ... implements
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner ... {}
public class Fragment implements
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner ... {}
ViewModelProvider
的get()
方法中返回VM
實(shí)例橘券,其中mFactory
為 SavedStateViewModelFactory
:
ViewModelProvider.java
----------------------
private static final String DEFAULT_KEY
= "androidx.lifecycle.ViewModelProvider.DefaultKey";
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
public <T extends ViewModel> T get(String key, Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
// 一個確保機(jī)制
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
}
// 正常以及基本的邏輯
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
SavedStateViewModelFactory
在后面解析。
- ViewModel 的屏幕橫豎屏切換恢復(fù)機(jī)制:
前面說到卿吐,創(chuàng)建VM
是通過ViewModelProvider
實(shí)現(xiàn)的旁舰,而ViewModelProvider
又是依賴ViewModelStore
進(jìn)行VM
的保存。
當(dāng)使用ComponentActivity
/Fragment
作為ViewModelProvider
的初始化參數(shù)時嗡官,實(shí)際VM
的儲存容器是參數(shù)提供的箭窜。
- ComponentActivity 實(shí)現(xiàn):
從源碼中,可以看出橫豎屏切換是直接通過NonConfigurationInstances
進(jìn)行恢復(fù)的衍腥。
ComponentActivity
包含一個NonConfigurationInstances
類磺樱,其中持有ViewModelStore
的引用:
ComponentActivity.java
----------------------
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
保存ViewModelStore
:
通過onRetainNonConfigurationInstance()
在橫豎屏切換中保存ViewModelStore
ComponentActivity.java
----------------------
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
// 從上一個 NonConfigurationInstances 中恢復(fù) ViewModelStore
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
// 保存當(dāng)前 ViewModelStore
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
在使用時嘗試通過getLastNonConfigurationInstance()
恢復(fù)ViewModelStore
:
ComponentActivity.java
----------------------
public ViewModelStore getViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// 通過 NonConfigurationInstances 對象直接恢復(fù) ViewModelStore
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
- Fragment 實(shí)現(xiàn):
要看懂該部分源碼,需要對FragmentManager有基礎(chǔ)了解婆咸,參考:深入理解FragmentManager
Fragment
的ViewModelStore
由FragmentManager
維護(hù)的FragmentManagerViewModel
管理竹捉。
- 注意這里使用了一個
VM
來維護(hù)一個ViewModelStore
Fragment.java
-------------
public ViewModelStore getViewModelStore() {
return mFragmentManager.getViewModelStore(this);
}
FragmentManager.java
--------------------
private FragmentManagerViewModel mNonConfig;
ViewModelStore getViewModelStore(Fragment f) {
return mNonConfig.getViewModelStore(f);
}
處理FragmentManagerViewModel
的實(shí)例化:
FragmentManager.java
--------------------
void attachController(FragmentHostCallback<?> host,
FragmentContainer container,
final Fragment parent) {
mHost = host;
mParent = parent;
if (parent != null) {
// 從父類的FM中獲取
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
// 假如 host 對象是實(shí)現(xiàn)了 ViewModelStoreOwner
// 則使用這個ViewModelStoreOwner的viewModelStore創(chuàng)建一個 FragmentManagerViewModel
ViewModelStore viewModelStore =
((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
// 生成一個不支持自動保存ViewModel的 FragmentManagerViewModel
mNonConfig = new FragmentManagerViewModel(false);
}
}
但從源碼注釋可以了解到,第三種情況已廢棄尚骄,理想情況下并不支持块差。
所以基本上,出現(xiàn)的應(yīng)該為第一倔丈、第二種情況憨闰。
host
對象實(shí)際是實(shí)現(xiàn)的ViewModelStoreOwner
接口的FragmentActivity$HostCallbacks
:
FragmentActivity.java
---------------------
class HostCallbacks
extends FragmentHostCallback<FragmentActivity>
implements ViewModelStoreOwner ... {...}
第二種情況,attachController()
傳入?yún)?shù)為null需五,可以理解為直接附著在FragmentActivity
上的Fragment
:
FragmentActivity.java
---------------------
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
}
FragmentController.java
-----------------------
public void attachHost(Fragment parent) {
mHost.mFragmentManager.attachController(mHost, mHost, parent);
}
而第一種情況鹉动,attachController()
傳入?yún)?shù)為Fragment
,在Fragment
的performAttach()
中調(diào)用:
Fragment.java
-------------
void performAttach() {
mChildFragmentManager.attachController(mHost, new FragmentContainer(), this)
}
...
解決了FragmentManagerViewModel
的來源宏邮,下面看看它的作用泽示。
上文提到,FragmentManagerViewModel
是一個VM
蜀铲,實(shí)際上可以聯(lián)想到可能是通過Activity
的ViewModelStore
边琉,使用相同的NonConfigurationInstances
機(jī)制實(shí)現(xiàn)的恢復(fù)。
先看第二種情況:
FragmentManager.java
--------------------
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
其中的host
為FragmentActivity$HostCallbacks
记劝,而getViewModelStore()
返回的實(shí)際上是FragmentActivity
的ViewModelStore
:
FragmentActivity$HostCallbacks.java
-----------------------------------
public ViewModelStore getViewModelStore() {
return FragmentActivity.this.getViewModelStore();
}
而FragmentManagerViewModel.getInstance()
內(nèi)部實(shí)際上是通過ViewModelProvider
返回一個本類VM
實(shí)例:
FragmentManagerViewModel .java
------------------------------
static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
ViewModelProvider viewModelProvider =
new ViewModelProvider(viewModelStore, FACTORY);
return viewModelProvider.get(FragmentManagerViewModel.class);
}
由于VM
在創(chuàng)建時变姨,會被儲存到對應(yīng)的ViewModelStore
,所以該VM
會存放到FragmentActivity
的ViewModelStore
中厌丑。
第一種情況:
實(shí)際上是頂級FragmentManager
的FragmentManagerViewModel
中定欧,維護(hù)一個子級的FragmentManagerViewModel
倉庫渔呵,然后通過頂級FragmentManagerViewModel
直接維護(hù)所有子級FragmentManagerViewModel
。
FragmentManagerViewModel .java
------------------------------
private final HashMap<String, FragmentManagerViewModel> mChildNonConfigs = new HashMap<>();
FragmentManagerViewModel getChildNonConfig(@NonNull Fragment f) {
FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
if (childNonConfig == null) {
childNonConfig = new FragmentManagerViewModel(mStateAutomaticallySaved);
mChildNonConfigs.put(f.mWho, childNonConfig);
}
return childNonConfig;
}
...
從以上源碼中可以看出砍鸠,Fragment
的橫豎屏切換恢復(fù)機(jī)制實(shí)際上是:
- 通過一個持有自身
ViewModelStore
引用的VM
扩氢,依附到Activity
的ViewModelStore
中,通過Activity
的機(jī)制進(jìn)行恢復(fù)爷辱。
其實(shí)這里引申一點(diǎn)的是录豺,源碼中提及到,NonConfigurationInstances
機(jī)制有可能在調(diào)用getLastNonConfigurationInstance
時返回null
饭弓,如需確保橫豎屏切換時的數(shù)據(jù)保存双饥,可以使用Fragment
的onSaveInstanceState(true)
,以Fragment
作為保存數(shù)據(jù)的容器弟断。
而事實(shí)上咏花,在舊版的ViewModel中,確實(shí)是通過
Fragment
的onSaveInstanceState(true)
進(jìn)行的阀趴。
- ViewModel 的后臺銷毀恢復(fù)機(jī)制:
前文提到昏翰,SavedStateViewModelFactory
是實(shí)現(xiàn)該機(jī)制的一部分,由SavedStateViewModelFactory
生成的VM
才具有在后臺銷毀前后通過SavedStateHandle
存取數(shù)據(jù)的特性刘急。
先看SavedStateViewModelFactory
的構(gòu)造方法:
SavedStateViewModelFactory.java
-------------------------------
public SavedStateViewModelFactory(Application application,
SavedStateRegistryOwner owner,
Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle = owner.getLifecycle();
mDefaultArgs = defaultArgs;
mApplication = application;
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
SavedStateViewModelFactory
在ComponentActivity
中實(shí)例化傳入的參數(shù)為:
ComponentActivity.java
----------------------
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
ComponentActivity
實(shí)現(xiàn)了SavedStateRegistryOwner
接口棚菊,該接口的實(shí)現(xiàn)類可以提供SavedStateRegistry
實(shí)例。
SavedStateRegistry
即是流程的關(guān)鍵對象之一排霉。
這里涉及到androidx提供的一個新的組件androidx.savedstate
:"該組件允許以插件方式窍株,將組件添加到SaveInstanceState
過程中"。
個人理解:
這是一套針對SavedState操作Bundle的封裝工具攻柠,但僅適用于系統(tǒng)實(shí)現(xiàn)球订。
因?yàn)榱鞒谭爆崳到y(tǒng)源碼在實(shí)現(xiàn)的過程中還包含了自動重建瑰钮,自動還原數(shù)據(jù)冒滩,生命周期確保等一系列操作。
而且當(dāng)你實(shí)現(xiàn)關(guān)鍵的SavedStateProvider
接口時浪谴,同樣要編寫B(tài)undle开睡,這和傳統(tǒng)的onSaveInstanceState()
區(qū)別不大。
因?yàn)橄到y(tǒng)實(shí)現(xiàn)了對VM
提供的存取操作苟耻,建議直接使用VM
篇恒,或者直接在onSaveInstanceState()
對數(shù)據(jù)進(jìn)行操作。
我后面有空會另行寫一篇文章去討論系統(tǒng)對該組件的實(shí)現(xiàn)凶杖。
ComponentActivity
實(shí)例化時胁艰,創(chuàng)建成員SavedStateRegistryController
,后者實(shí)例化時,創(chuàng)建成員SavedStateRegistry
:
ComponentActivity.java
----------------------
private final SavedStateRegistryController mSavedStateRegistryController =
SavedStateRegistryController.create(this);
SavedStateRegistryController.java
---------------------------------
public static SavedStateRegistryController create(SavedStateRegistryOwner owner) {
return new SavedStateRegistryController(owner);
}
private SavedStateRegistryController(SavedStateRegistryOwner owner) {
mOwner = owner;
mRegistry = new SavedStateRegistry();
}
ComponentActivity
在onSaveInstanceState()
中調(diào)用SavedStateRegistryController.performSave()
腾么,內(nèi)部實(shí)際調(diào)用SavedStateRegistry.performSave()
:
ComponentActivity.java
----------------------
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mSavedStateRegistryController.performSave(outState);
}
SavedStateRegistryController.java
---------------------------------
public void performSave(Bundle outBundle) {
mRegistry.performSave(outBundle);
}
SavedStateRegistry
會把所有注冊到自身的SavedStateProvider
奈梳,通過saveState()
提取數(shù)據(jù),并保存到一個Bundle
中:
SavedStateRegistry.java
-----------------------
void performSave(@NonNull Bundle outBundle) {
Bundle components = new Bundle();
for (Iterator<Map.Entry<String, SavedStateProvider>> it =
mComponents.iteratorWithAdditions(); it.hasNext(); ) {
Map.Entry<String, SavedStateProvider> entry1 = it.next();
components.putBundle(entry1.getKey(), entry1.getValue().saveState());
}
outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
}
至此解虱,說明數(shù)據(jù)保存的發(fā)起攘须,最終通知到SavedStateRegistry
。
先看SavedStateProvider
接口:
注冊到SavedStateRegistry
中實(shí)現(xiàn)類殴泰,會在SavedStateRegistry
保存過程將會調(diào)用saveState()
獲取數(shù)據(jù)于宙。
而稍后(在恢復(fù)數(shù)據(jù)時),將會通過SavedStateRegistry.consumeRestoredStateForKey()
取出保存的數(shù)據(jù)悍汛。
SavedStateProvider
通過SavedStateRegistry.registerSavedStateProvider()
注冊到SavedStateRegistry
:
SavedStateRegistry.java
-----------------------
public void registerSavedStateProvider(String key, SavedStateProvider provider) {
SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
if (previous != null) {
throw new IllegalArgumentException(
"SavedStateProvider with the given key is already registered");
}
}
到此限煞,說明儲存數(shù)據(jù)的提供者,是注冊到SavedStateRegistry
中的SavedStateProvider
员凝。
前文提及,VM
的存取核心是SavedStateHandle
奋献,那么說明SavedStateProvider
和SavedStateHandle
存在必然的關(guān)聯(lián)健霹。
實(shí)際上,SavedStateHandle
實(shí)例中瓶蚂,維護(hù)一個SavedStateProvider
匿名內(nèi)部類實(shí)例糖埋,而SavedStateHandle
的讀寫和SavedStateProvider
實(shí)例的數(shù)據(jù)讀取操作,都是對實(shí)際數(shù)據(jù)容器mRegular
讀寫窃这。
先看SavedStateHandle
:
前文提到瞳别,最終該機(jī)制的實(shí)現(xiàn),實(shí)際為
SaveInstanceState
機(jī)制杭攻,則反映VM
并不會對數(shù)據(jù)進(jìn)行自動存取祟敛。
事實(shí)上VM
確實(shí)需要手動將后臺銷毀前保存的數(shù)據(jù)放到SaveInstanceState
中,SavedStateHandle
確實(shí)是這么用的兆解,所以提供了一系列的get
/set
操作馆铁,而最終還要編寫SavedStateProvider
的Bundle
轉(zhuǎn)換操作。同時可以看出锅睛,
SavedStateHandle
提供了對LiveData
的存取支持埠巨。
SavedStateHandle
對LiveData
的支持,來自對LiveData
的內(nèi)部的靜態(tài)包裝類SavingStateLiveData
现拒。
SavingStateLiveData
包裝了setValue()
辣垒,傳入的參數(shù)會被優(yōu)先儲存到mRegular
中。
用于提取數(shù)據(jù)的SavedStateProvider
:
需要編寫SavedStateProvider
數(shù)據(jù)的Bundle
轉(zhuǎn)換操作印蔬。
所以如無必要勋桶,無需自定義該組件,建議在onSaveInstanceState()
中直接操作。
SavedStateHandle.java
---------------------
// 最終的數(shù)據(jù)容器主體
// initialState為構(gòu)造時參入的上次SavedInstanceState產(chǎn)生的舊數(shù)據(jù)
// 既 SavedStateHandle.createHandle 時傳入的參數(shù)哥遮,下面會說明
final Map<String, Object> mRegular = new HashMap<>(initialState);
// SavedStateProvider 對數(shù)據(jù)主體 mRegular 進(jìn)行處理并生成一個Bundle
private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
public Bundle saveState() {
Set<String> keySet = mRegular.keySet();
ArrayList keys = new ArrayList(keySet.size());
ArrayList value = new ArrayList(keys.size());
for (String key : keySet) {
keys.add(key);
value.add(mRegular.get(key));
}
Bundle res = new Bundle();
// "parcelable" arraylists - lol
res.putParcelableArrayList("keys", keys);
res.putParcelableArrayList("values", value);
return res;
}
};
至此岂丘,SavedStateHandle
和SavedStateProvider
實(shí)現(xiàn)關(guān)聯(lián)。
前文提及眠饮,SavedStateProvider
通過SavedStateRegistry.registerSavedStateProvider()
注冊到SavedStateRegistry
:
而該方法的調(diào)用奥帘,則是通過SavedStateHandleController
進(jìn)行的。
SavedStateHandleController
的實(shí)例化則是通過SavedStateViewModelFactory
進(jìn)行的仪召,最終回到了SavedStateViewModelFactory
寨蹋。
先看SavedStateViewModelFactory
:
通過調(diào)用SavedStateHandleController.create()
返回SavedStateHandleController
實(shí)例。
同時扔茅,VM
在創(chuàng)建時已旧,傳入了SavedStateHandleController
的SavedStateHandle
實(shí)例作為參數(shù),即VM
和SavedStateHandle
進(jìn)行了綁定召娜。
SavedStateViewModelFactory.java
-------------------------------
public <T extends ViewModel> T create(String key, Class<T> modelClass) {
// 判斷是否是AVM
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
if (isAndroidViewModel) {
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
// 如果不需要SavedStateHandle运褪,則直接創(chuàng)建一個普通的VM/AVM
if (constructor == null) {
return mFactory.create(modelClass);
}
// 創(chuàng)建了 SavedStateHandleController
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
// VM 在創(chuàng)建的時候持有了SavedStateHandleController內(nèi)維護(hù)的SavedStateHandle對象
try {
T viewmodel;
if (isAndroidViewModel) {
viewmodel = constructor.newInstance(mApplication, controller.getHandle());
} else {
viewmodel = constructor.newInstance(controller.getHandle());
}
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
return viewmodel;
...
}
再看SavedStateHandleController .create()
:
SavedStateHandle
在實(shí)例化時,通過consumeRestoredStateForKey()
傳入上次保存的數(shù)據(jù)玖瘸,此時SavedStateHandle
數(shù)據(jù)已完成恢復(fù)秸讹。
SavedStateHandleController
創(chuàng)建后,通過attachToLifecycle()
方法雅倒,在方法內(nèi)部將SavedStateHandle
維護(hù)的SavedStateProvider
注冊到SavedStateRegistry
璃诀。
前面說到SavedStateViewModelFactory
是框架骨架之一,實(shí)際就是通過這個過程蔑匣,最終允許VM
能夠把數(shù)據(jù)的存取加入到SaveInstanceState
流程劣欢。
SavedStateHandleController.java
-------------------------------
static SavedStateHandleController create(SavedStateRegistry registry,
Lifecycle lifecycle, String key, Bundle defaultArgs) {
// 通過consumeRestoredStateForKey獲取前次狀態(tài)
Bundle restoredState = registry.consumeRestoredStateForKey(key);
// 創(chuàng)建一個Handle
SavedStateHandle handle =
SavedStateHandle.createHandle(restoredState, defaultArgs);
// 生成SavedStateHandleController實(shí)例
SavedStateHandleController controller =
new SavedStateHandleController(key, handle);
// 這里進(jìn)行了綁定
controller.attachToLifecycle(registry, lifecycle);
tryToAddRecreator(registry, lifecycle);
return controller;
}
void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());
}
至此,SavedStateProvider
和SavedStateRegistry
實(shí)現(xiàn)關(guān)聯(lián)裁良。
以上就是整個保存流程的概況凿将,而還原流程差距不大,只是在onCreate()
中調(diào)用SavedStateRegistryController.performRestore()
价脾,最終通知SavedStateRegistry
在Bundle
中恢復(fù)設(shè)置的數(shù)據(jù)丸相。
忽略SavedStateHandleController
對VM
的確保機(jī)制 (包含Recreator
),最后總結(jié):
- 簡化稱呼以縮短閱讀量:
--
VM組:
ViewModel
=VM
SavedStateViewModelFactory
=Factory
--
Registry組:
SavedStateRegistryController
=RegistryController
SavedStateRegistry
=Registry
--
Handle組:
SavedStateHandleController
=HandleController
SavedStateHandle
=Handle
--
Provider組:
SavedStateProvider
=Provider
--
初始化階段:
ComponentActivity
創(chuàng)建了RegistryController
實(shí)例
RegistryController
創(chuàng)建了內(nèi)部的Registry
實(shí)例
ComponentActivity
創(chuàng)建了Factory
彼棍,并傳入RegistryController
維護(hù)的Registry
恢復(fù)階段
ComponentActivity
在onCreate
調(diào)用RegistryController
的performRestore
RegistryController
的performRestore
中灭忠,調(diào)用Registry
的performRestore
Registry
的performRestore
中,把數(shù)據(jù)從savedInstanceState (Bundle)
取出座硕,并儲存到mRestoredState
中
在此處Registry
已把數(shù)據(jù)恢復(fù)VM生成階段:
VM
需要通過Factory
創(chuàng)建弛作,創(chuàng)建過程:
-- 創(chuàng)建VM
對應(yīng)的HandleController
實(shí)例,創(chuàng)建過程:
------ 通過Registry
的consumeRestoredStateForKey
把數(shù)據(jù)取出生成Handle
------Handle
內(nèi)部維護(hù)一個Provider
實(shí)例华匾,共享數(shù)據(jù)容器mRegular
------HandleController
被注入Handle
------Provider
綁定到Registry
------ 在此處實(shí)現(xiàn)了 (RegistryController
-Registry
-Provider
-Handle
) 綁定
--VM
被Factory
注入Handle
--在此處實(shí)現(xiàn)了 (RegistryController
-Registry
-Provider
-Handle-VM
) 綁定
--VM
數(shù)據(jù)最終通過Registry
恢復(fù)寫數(shù)據(jù)階段
VM
讀寫的數(shù)據(jù)最終存放到Handle
的mRegular
中
VM
數(shù)據(jù)最終通過Registry
保存保存階段
ComponentActivity
在onSaveInstanceState
調(diào)用RegistryController
的performSave
RegistryController
的performSave
中映琳,調(diào)用Registry
的performSave
Registry
的performSave
中机隙,將所有注冊的Provider
數(shù)據(jù)打包成一個Bundle
保存到onSaveInstanceState
的Bundle
中
在此處Registry
已把數(shù)據(jù)保存
·