寫在前面
組件架構(gòu)三劍客終于來到了最后一篇:ViewModel蚣旱,關(guān)于Lifecycle和LiveData可以看之前的文章配紫。ViewModel和Lifecycle和LiveData的關(guān)聯(lián)并不大债鸡,可以單獨拿出來使用诱鞠。這里用的依賴主要是AndroidX里面的,其他版本可能有些不同镣丑,但核心邏輯應(yīng)該還是一致的宣谈。
implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0-alpha01'
我們都知道,ViewModel的核心功能之一就是幫我們保存數(shù)據(jù)肄梨,特別是當(dāng)Activity重建時還能將數(shù)據(jù)保存下來阻荒。頁面重建保存數(shù)據(jù),看到這里我們可能很容易的就想到了onSaveInstanceState()
方法峭范,我們可以在這里保存數(shù)據(jù)财松,以便Activity重新創(chuàng)建時在onCreate()
方法中接收到保存下來的數(shù)據(jù)瘪贱。但它是有局限的纱控,只能保存一些簡單的數(shù)據(jù)或者一些經(jīng)過序列化的數(shù)據(jù),并且數(shù)據(jù)量還不能太大菜秦。ViewModel的出現(xiàn)甜害,正好彌補了這一不足。
ViewModel結(jié)構(gòu)與Lifecycle的結(jié)構(gòu)類似球昨,Activity/Fragment除了實現(xiàn)一個LifecycleOwner接口外尔店,還實現(xiàn)了一個ViewModelStoreOwner接口,它只有一個方法用來獲取ViewModelStore,然后通過ViewModelStore來負責(zé)添加和移除ViewModel嚣州。
ViewModelProvider
ViewModel的創(chuàng)建是ViewModelProvider提供的鲫售。要看ViewModel是怎么被創(chuàng)建并添加進ViewModelStore的,還得先從我們最熟悉的api入手该肴。
// 這里的this是指Activity
viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
先創(chuàng)建一個ViewModelProvider情竹,再通過它來獲取ViewModel。
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
this(store, new FactoryWrapper(factory));
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull KeyedFactory factory) {
// 要注意這里的mFactory是KeyedFactory
mFactory = factory;
mViewModelStore = store;
}
Factory
這個方法的目的是要構(gòu)造一個ViewModelProvider匀哄,先來講講工廠Factory秦效,ViewModelStore
放到后面講。默認我們沒有傳工廠進來涎嚼,這里會幫我們構(gòu)建一個AndroidViewModelFactory對象阱州。因為這里面出現(xiàn)了很多Factory相關(guān)的類,所以我覺得還是有必要先將Factory的結(jié)構(gòu)講一下法梯,有助于了解苔货。
結(jié)合上面的代碼和類圖來看,這個框架會默認給我們提供一個AndroidViewModelFactory工廠對象立哑,然后又將它封裝成了一個KeyedFactory對象蒲赂,再加上ViewModelStore對象,一起構(gòu)造出了ViewModelProvider刁憋。短短的一個方法里面出現(xiàn)了工廠模式(Factory)和裝飾器模式(FactoryWrapper)滥嘴,真的是很佩服。
ViewModel
拿到ViewModelProvider對象后至耻,再來看它的get方法:
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
// mFactory指的是FactoryWrapper
viewModel = mFactory.create(key, modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
首先是根據(jù)class獲取一個key值若皱,然后先從mViewModelStore中查詢有沒有相應(yīng)的ViewModel,當(dāng)然我們第一次調(diào)用肯定是拿不到的尘颓,需要走下面的創(chuàng)建步驟,創(chuàng)建完再添加到ViewModelStore中去走触。
private static class FactoryWrapper implements KeyedFactory {
private final Factory mFactory;
FactoryWrapper(Factory factory) {
mFactory = factory;
}
@Override
public <T extends ViewModel> T create(String key, Class<T> modelClass) {
// mFactory指的是AndroidViewModelFactory
return mFactory.create(modelClass);
}
}
很奇怪的是這里的key并沒有被用到,不知道后面會不會添加一些新的東西進來疤苹。
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (...) {
// 一些catch
}
}
return super.create(modelClass);
}
如果這個ViewModel是繼承自AndroidViewModel的話互广,就用AndroidViewModelFactory創(chuàng)建一個,否則卧土,用NewInstanceFactory創(chuàng)建一個普通的ViewModel惫皱。
Android給的建議是不要在ViewModel中使用到任何與Android相關(guān)的代碼,最簡單的檢查辦法就是看有沒有import進*.android.*
相關(guān)的東西尤莺。但是這又有點不現(xiàn)實旅敷,因為我們經(jīng)常需要用到Context去獲取一些資源。為了解決這個問題颤霎,Android就給我們提供了AndroidViewModel媳谁。所以如果有這個需求的話可以讓你的ViewModel繼承AndroidViewModel涂滴。
另外,從ViewModel的創(chuàng)建過程來看晴音,如果我們需要在構(gòu)造函數(shù)里傳一些別的參數(shù)的話柔纵,就需要自己去構(gòu)建工廠類了。
講完了Factory锤躁,再回過頭來看ViewModelStore首量,Activity/Fragment創(chuàng)建ViewModel的過程唯一的區(qū)別就在于ViewModelStore獲取方式的不同。
activity.getViewModelStore();
fragment.getViewModelStore();
Activity.getViewModelStore()
@NonNull
@Override
public ViewModelStore getViewModelStore() {
......
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
首次調(diào)用這個方法进苍,肯定是通過new方法拿到的加缘,可以猜出ViewModelStore的緩存就是通過NonConfigurationInstances緩存下來的。而它又是在onRetainNonConfigurationInstance()
方法中保存下來的觉啊,然后使用getLastNonConfigurationInstance()
獲取出來的拣宏。這個與onSaveInstanceState()
和onRestoreInstanceState()
是類似的。
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
關(guān)于onRetainNonConfigurationInstance()
和getLastNonConfigurationInstance()
這兩個方法可以來Activity中看一下具體的流程杠人。首先狀態(tài)得保存下來勋乾,才能在重建的時候取出來。既然是要保存狀態(tài)嗡善,那肯定是在onDestroy()
的時候保存的辑莫,所以直接來看看ActivityThread$performDestroyActivity()
// ActivityThread.java
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
ActivityClientRecord r = mActivities.get(token);
Class<? extends Activity> activityClass = null;
if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
if (r != null) {
activityClass = r.activity.getClass();
r.activity.mConfigChangeFlags |= configChanges;
if (finishing) {
r.activity.mFinished = true;
}
// 如果還沒調(diào)用onPause()的話,調(diào)用onPause()
performPauseActivityIfNeeded(r, "destroy");
if (!r.stopped) {
// 調(diào)用onStop()
callActivityOnStop(r, false /* saveState */, "destroy");
}
if (getNonConfigInstance) {
try {
// 劃重點罩引,保存狀態(tài)
r.lastNonConfigurationInstances
= r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to retain activity "
+ r.intent.getComponent().toShortString()
+ ": " + e.toString(), e);
}
}
}
try {
r.activity.mCalled = false;
// 調(diào)用onDestroy()
mInstrumentation.callActivityOnDestroy(r.activity);
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + safeToComponentShortString(r.intent) +
" did not call through to super.onDestroy()");
}
if (r.window != null) {
r.window.closeAllPanels();
}
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
"Unable to destroy activity " + safeToComponentShortString(r.intent)
+ ": " + e.toString(), e);
}
}
r.setState(ON_DESTROY);
}
mActivities.remove(token);
StrictMode.decrementExpectedActivityCount(activityClass);
return r;
}
再繼續(xù)跟到Activity里面
NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
mFragments.doLoaderStart();
mFragments.doLoaderStop(true);
ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();
if (activity == null && children == null && fragments == null && loaders == null
&& mVoiceInteractor == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
第一行就是調(diào)用onRetainNonConfigurationInstance()
來保存Activity的狀態(tài)各吨。這個方法返回的NonConfigurationInstances對象保存在ActivityClientRecord中,然后在重啟Activity的onAttach()
方法中將NonConfigurationInstances拿回來袁铐,從而實現(xiàn)了數(shù)據(jù)的不丟失揭蜒。
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) {
......
// 取回NonConfigurationInstances
mLastNonConfigurationInstances = lastNonConfigurationInstances;
}
Fragment.getViewModelStore()
// Fragment.java
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
return mFragmentManager.getViewModelStore(this);
}
// FragmentManagerImpl.java
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
// FragmentManagerViewModel.java
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore == null) {
viewModelStore = new ViewModelStore();
mViewModelStores.put(f.mWho, viewModelStore);
}
return viewModelStore;
}
可以看到,最后是通過FragmentManagerViewModel來保存ViewModelStore的剔桨,key是相應(yīng)的Fragment的ID屉更。哦對了,F(xiàn)ragmentManagerViewModel自己也是一個ViewModel洒缀。
Fragment的數(shù)據(jù)恢復(fù)是在FragmentActivity$onCreate()
里面做的瑰谜。
@SuppressWarnings("deprecation")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 在這里恢復(fù)數(shù)據(jù)
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
......
}
最終走到FragmentManagerImpl中去:
public void attachController(@NonNull FragmentHostCallback host,
@NonNull FragmentContainer container, @Nullable Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
if (parent != null) {
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
// 這里是通過Activity的getViewModelStore()獲取ViewModelStore的
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false);
}
}
在這里初始化mNonConfig
,所以我們才能通過mNonConfig.getViewModelStore()
去獲取ViewModelStore树绩。重新創(chuàng)建Activity的時候萨脑,是通過Activity的getViewModelStore()
去拿到ViewModelStore的,再通過它去拿到FragmentManagerViewModel葱峡。這里感覺有點繞砚哗×可以這么說吧砰奕,F(xiàn)ragment的ViewModelStore是存放到FragmentManagerViewModel中的蛛芥,然后FragmentManagerViewModel又被放到了Activity的ViewModelStore中,Activity在保存數(shù)據(jù)的時候自然也就將FragmentManagerViewModel保存了下來军援,從而將Fragment的ViewModelStore保存了下來仅淑。
另外,網(wǎng)上有一些文章說Fragment的ViewModelStore是通過Fragment$setRetainInstance()
來保存的胸哥,可能是引用的版本號不一樣吧涯竟,畢竟Android還在繼續(xù)更新中。我這里通過調(diào)試發(fā)現(xiàn)是以這種方式保存的空厌÷可能以后版本不一樣又會有所改動了。
最后
到這里嘲更,Lifecycle, LiveData和ViewModel的原理筐钟,總算是解析完了。其中至少是用到了觀察者模式赋朦,工廠模式篓冲,裝飾器模式,自己分析完之后還是有所收獲的宠哄。也可以看到ViewModel的原理和Activity的生命周期最加緊密壹将,先給自己挖個坑,后面找時間再來寫一篇Activity的啟動流程的毛嫉。