ViewModel是Google官方MVVM架構(gòu)的核心組件之一。同時,在Google推出的Android Jetpack組件中,也將ViewModel放在了Architecture類別之中。ViewModel類旨在以一種有生命周期的方式存儲和管理與UI相關(guān)的數(shù)據(jù),并且不會因?yàn)槠聊恍D(zhuǎn)等配置變化后而銷毀。

從ViewModel生命周期圖中可以看出我們發(fā)現(xiàn),當(dāng)activity因屏幕旋轉(zhuǎn)而銷毀,但是ViewModel一直存在,正是因?yàn)閂iewModel有如此的生命周期,所以ViewModel在MVVM中可以作為數(shù)據(jù)存儲區(qū),是連接View和Model重要組件。
本文主要通過分析ViewModel源碼,搞清楚如下幾個問題:
- ViewModel是如何創(chuàng)建的?
- ViewModel是如何存儲的,具體放在哪?
- ViewModel如何實(shí)現(xiàn)旋轉(zhuǎn)屏幕而不銷毀?
一、ViewModel創(chuàng)建過程
使用過ViewModel的同學(xué)都應(yīng)該知道,當(dāng)我們想要創(chuàng)建一個ViewModel對象的時候,不是通過new關(guān)鍵字去創(chuàng)建的,而是通過ViewModelProviders.of(this).get(ViewModel.class)這種調(diào)用方式創(chuàng)建的,簡言之就是通過ViewModelProviders去創(chuàng)建。其實(shí),我們想想也可以知道,ViewModel想要有生命周期,那么它勢必就要和我們的Activity或者Fragment相關(guān)聯(lián)起來,至于如何關(guān)聯(lián),源碼會給我們答案。
我們先來看下ViewModelProviders.of()方法,調(diào)用這個方法最終會走到下面這2個方法其中之一,一個是在Activity里面調(diào)用,另一個則是在Fragment中調(diào)用:
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
Application application = checkApplication(checkActivity(fragment));
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
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(ViewModelStores.of(activity), factory);
}
我們看到這個方法最終會返回一個ViewModelProvider對象,在生成這個對象的時候需要傳遞2個參數(shù),第一個參數(shù)是ViewModelStore,第二個參數(shù)是Factory。第一參數(shù)我們等到討論ViewModel具體是存儲在哪邊的時候再說,暫且略過。這邊先重點(diǎn)看下第二個參數(shù)Factory,從代碼上來看,如何我們沒有顯示地傳入Factory對象的話,就會去拿一個默認(rèn)的Factory對象。事實(shí)也就是如此,而且這個默認(rèn)的Factory對象還是個單例。其實(shí),AndroidViewModelFactory就是ViewModelProvider的一個靜態(tài)內(nèi)部類,具體代碼如下所示:
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private static AndroidViewModelFactory sInstance;
@NonNull
public static AndroidViewModelFactory getInstance(@NonNull Application application) {
if (sInstance == null) {
sInstance = new AndroidViewModelFactory(application);
}
return sInstance;
}
private Application mApplication;
public AndroidViewModelFactory(@NonNull Application application) {
mApplication = application;
}
@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 (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
}
至此,我們的ViewModelProvider對象總算是創(chuàng)建完成了,接下來就要調(diào)用它的get()方法來具體創(chuàng)建我們所需要的ViewModel對象了,具體如下:
// ViewModelProvider # get(@NonNull Class<T> modelClass)
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);
}
// ViewModelProvider # get(@NonNull String key, @NonNull Class<T> modelClass)
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.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
由上述代碼我們可以知道,對于我們想要獲取的ViewModel對象,首先會根據(jù)key從mViewModelStore中去尋找,看看是否已經(jīng)創(chuàng)建過,如果找到則直接返回。如果之前沒有創(chuàng)建過,則調(diào)用mFactory的create()方法去創(chuàng)建,如果我們沒有顯示地傳入Factory對象,則調(diào)用默認(rèn)的Factory對象(即AndroidViewModelFactory單例對象)去創(chuàng)建,由AndroidViewModelFactory源碼可知它的create()方法會通過反射去創(chuàng)建我們的ViewModel對象。在創(chuàng)建完畢之后,就會把這個ViewModel對象存入mViewModelStore之中,那么很明顯這個mViewModelStore內(nèi)部肯定是一個HashMap結(jié)構(gòu)。至此,我們已經(jīng)將ViewModel創(chuàng)建過程解析完畢了,接下來看下創(chuàng)建好的ViewModel是存儲在什么地方的。
二、ViewModel存儲位置
在解析ViewModel創(chuàng)建過程時,我們遺漏了一個點(diǎn),那就是創(chuàng)建ViewModelProvider對象時傳入的第一個參數(shù)ViewModelStore,它是通過ViewModelStores.of(activity)或者ViewModelStores.of(fragment)來創(chuàng)建的。其實(shí),創(chuàng)建出來的ViewModelStore對象最后復(fù)制給了我們上面所提到的mViewModelStore,具體可以看下如下源碼:
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
而我們通過分析ViewModel創(chuàng)建過程,知道了最終創(chuàng)建出來的ViewModel對象,就是存儲在mViewModelStore之中的。那么,現(xiàn)在就很明顯了,ViewModel的存儲位置其實(shí)就是mViewModelStore的存儲位置,我們需要搞清楚ViewModelStores.of()方法的執(zhí)行過程就行。
public static ViewModelStore of(@NonNull FragmentActivity activity) {
if (activity instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) activity).getViewModelStore();
}
return holderFragmentFor(activity).getViewModelStore();
}
public static ViewModelStore of(@NonNull Fragment fragment) {
if (fragment instanceof ViewModelStoreOwner) {
return ((ViewModelStoreOwner) fragment).getViewModelStore();
}
return holderFragmentFor(fragment).getViewModelStore();
}
我們具體看下ViewModelStores.of()方法的執(zhí)行過程,由于我們的Activity或者Fragment一般不會去實(shí)現(xiàn)ViewModelStoreOwner接口,所以基本都是通過holderFragmentFor(xxx).getViewModelStore()這種方式去創(chuàng)建ViewModelStore對象。
那么,我們先來看下這個創(chuàng)建方式的前半段holderFragmentFor(xxx):
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
public static HolderFragment holderFragmentFor(Fragment fragment) {
return sHolderFragmentManager.holderFragmentFor(fragment);
}
很明顯,這個方法返回的是一個HolderFragment對象,而且它繼承自Fragment。HolderFragment對象的創(chuàng)建都是通過調(diào)用sHolderFragmentManager.holderFragmentFor()方法實(shí)現(xiàn)的,那么這個sHolderFragmentManager其實(shí)是HolderFragment內(nèi)部類HolderFragmentManager的對象,我們一起看下它的holderFragmentFor()方法,這里以入?yún)锳ctivity為例:
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
holder = mNotCommittedActivityHolders.get(activity);
if (holder != null) {
return holder;
}
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
holder = createHolderFragment(fm);
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
private static HolderFragment findHolderFragment(FragmentManager manager) {
if (manager.isDestroyed()) {
throw new IllegalStateException("Can't access ViewModels from onDestroy");
}
Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
throw new IllegalStateException("Unexpected "
+ "fragment instance was returned by HOLDER_TAG");
}
return (HolderFragment) fragmentByTag;
}
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
HolderFragment holder = new HolderFragment();
fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
return holder;
}
private ActivityLifecycleCallbacks mActivityCallbacks =
new EmptyActivityLifecycleCallbacks() {
@Override
public void onActivityDestroyed(Activity activity) {
HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
if (fragment != null) {
Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
}
}
};
由源碼可知,會先去查找Tag為HOLDER_TAG的HolderFragment是否已經(jīng)創(chuàng)建過,如果已經(jīng)創(chuàng)建過則直接返回,從這我們可以得到的信息是一個Activity/Fragment只會創(chuàng)建一個HolderFragment。如果沒有找到,則會從mNotCommittedActivityHolders緩存中進(jìn)行查找,同樣如果找到就直接返回。如果仍然沒有找到,則說明之前未創(chuàng)建過,則調(diào)用createHolderFragment()方法創(chuàng)建HolderFragment對象,并在完成創(chuàng)建之后存入mNotCommittedActivityHolders。同時,我們還注意到,這里還注冊了Activity生命周期監(jiān)聽,目的是在Activity銷毀的時候可以移除mNotCommittedActivityHolders中的對應(yīng)數(shù)據(jù)。
之后,在拿到HolderFragment對象之后,通過調(diào)用它的getViewModelStore()方法就可以拿到ViewModelStore對象了,它其實(shí)就是HolderFragment的成員變量。
public ViewModelStore getViewModelStore() {
return mViewModelStore;
}
至此,通過以上分析,我們知道通過ViewModelStores.of()方法獲取的ViewModelStore對象其實(shí)就是HolderFragment的成員變量。那么,也就是說我們創(chuàng)建的ViewModel對象其實(shí)也就是保存在所創(chuàng)建出來無UI的HolderFragment之中的。需要注意的一點(diǎn)是,對于同一個Activity/Fragment而言,這種無UI的HolderFragment只會存在一個,但是存在HolderFragment之中的ViewModel可以有多個,即一個Activity/Fragment可以對應(yīng)多個ViewModel對象。
三、ViewModel旋轉(zhuǎn)屏幕不銷毀原理
ViewModel旋轉(zhuǎn)屏幕不銷毀的原理其實(shí)就在HolderFragment的構(gòu)造方法之中。
public HolderFragment() {
setRetainInstance(true);
}
@Override
public void onDestroy() {
super.onDestroy();
mViewModelStore.clear();
}
/**
* Control whether a fragment instance is retained across Activity
* re-creation (such as from a configuration change). This can only
* be used with fragments not in the back stack. If set, the fragment
* lifecycle will be slightly different when an activity is recreated:
* <ul>
* <li> {@link #onDestroy()} will not be called (but {@link #onDetach()} still
* will be, because the fragment is being detached from its current activity).
* <li> {@link #onCreate(Bundle)} will not be called since the fragment
* is not being re-created.
* <li> {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} <b>will</b>
* still be called.
* </ul>
*/
public void setRetainInstance(boolean retain) {
mRetainInstance = retain;
}
由源碼可知,setRetainInstance(boolean) 是Fragment中的一個方法。根據(jù)官方注釋,我們可以知道,當(dāng)設(shè)置setRetainInstance(true)時,當(dāng)我們旋轉(zhuǎn)屏幕的時候,Activity會重繪,但是Fragment不會重繪,它將會保留,這也就意味著旋轉(zhuǎn)屏幕時Fragment的onCreate和onDestory方法都不會調(diào)用。
無UI的HolderFragment正是運(yùn)用了這個特性,在其中存放一個專門用于存儲ViewModel對象的ViewModelStore(其內(nèi)部為HashMap),如此ViewModelStore中所有的ViewModel都不會因?yàn)槠聊恍D(zhuǎn)等配置變化后而銷毀。
總結(jié)
在創(chuàng)建ViewModel對象的過程中,會生成一個無UI的HolderFragment。對于同一個Activity/Fragment,只會有一個HolderFragment,但是可以有多個ViewModel。ViewModel存儲在無UI的HolderFragment中,具體以鍵值對形式存儲在ViewModelStore的HashMap中。Activity/Fragment的HolderFragment會保存在全局單例的HolderFragmentManager的HashMap中,在Activity/Fragment銷毀時會進(jìn)行相應(yīng)的移除。