前言
这里有个基础知识需要了解一下,AppCompatActivity继承了FragmentActivity继承了ComponentActivity继承了Activity,在这里的讲解我们是以继承AppCompatActivity为基础的情况下说明。
1.ViewModel创建流程
- mViewModel = ViewModelProviders.of(this).get(vm.class)
- mViewModel = ViewModelProvider(this).get(vm.class)
这里第一种方式已经过时废弃了,可以使用第二种,其实第一种方式后面调用还是使用的下面这个方法,这里我们就直接分析第二个方法了。
这里可以看到,初始化过程分为两步,先初始化ViewModelProvider,我们来看一下源码:
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
这里的ViewModelStoreOwner就传入当前的AppCompatActivity或者Fragment就可以了,我们看一下ViewModelStoreOwner源码:
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
他是一个接口,Fragment,FragmentActivity等都实现了这个接口。下面我们来看一下ViewModelStore是什么:
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
ViewModelStore里面有一个HashMap,这个HashMap是用来存放ViewModel,还提供了一个clear()方法,这个方法里的操作很简单,就是调用存放ViewModel的onCleared()方法,以及清空HashMap。ViewModel其实很简单,就是个抽象类,里面有个onCleared()方法。
下面我们来看看ViewModelProvider(ViewModelStoreOwner)随后调用了ViewModelProvider(ViewModelStore, Factory)方法,我们来看一下getViewModelStore()的源码,是如何创建ViewModelStore的,这里我们看Activity的:
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
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;
}
这里我们可以看到,先判断是否需要还原ViewModelStore,这个后面会再讲到;然后就是实例化一个ViewModelStore返回。下面我们来看一下Factory是怎么来的:
owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance()
可以看到,他会判断传入的activity是否有是HasDefaultViewModelProviderFactory,他是一个接口,ComponentActivity、Fragment都实现了这个接口,我们看一下ComponentActivity中getDefaultViewModelProviderFactory()方法:
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mDefaultFactory == null) {
mDefaultFactory = new SavedStateViewModelFactory(
getApplication(),
this,
getIntent() != null ? getIntent().getExtras() : null);
}
return mDefaultFactory;
}
继续看SavedStateViewModelFactory()方法:
public SavedStateViewModelFactory(@NonNull Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle = owner.getLifecycle();
mDefaultArgs = defaultArgs;
mApplication = application;
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
可以看到这个Factory就是ViewModelProvider.AndroidViewModelFactory单列
下面我们再来看get(vm.class)方法:
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);
}
继续:
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
这里使用mFactory创建出viewModel,调用就是AndroidViewModelFactory的create()方法:
@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);
}
然后将viewModel存储到ViewModelStore中,到这里ViewModel就创建完成了。
2.ViewModel的生命周期
这张ViewModel生命周期图时谷歌官方提供的,从这上面显示activity在横竖屏旋转重建时ViewModel也是一直存在内存中。
经过ViewModel创建的源码分析,我们知道ViewModel是存放在ViewModelStore中的,ViewModelStore有clear()方法用来清除存放的ViewModel,我们先来找一下这个ViewModelStore.clear()在哪里调用:
Fragment中销毁
public void onDestroy() {
mCalled = true;
FragmentActivity activity = getActivity();
boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations();
if (mViewModelStore != null && !isChangingConfigurations) {
mViewModelStore.clear();
}
}
这里是在onDestroy()方法中调用的,注意这里有个判断!isChangingConfigurations(),这是横竖屏切换时不会去销毁ViewModel。
FragmentActivity中销毁
protected void onDestroy() {
super.onDestroy();
if (mViewModelStore != null && !isChangingConfigurations()) {
mViewModelStore.clear();
}
mFragments.dispatchDestroy();
}
这里还是在onDestroy()方法中调用的,且横竖屏切换时不会去销毁ViewModel。
这里可以知道当页面销毁的时候ViewModel也是会被销毁的,但是横竖屏切换不去销毁,那么按照常理来讲不销毁就是想复用,也就是说在Activity横竖屏切换重建页面的时候,ViewModel是不销毁的需要复用,那么我们就来找找他是如何复用的。
FragmentActivity中恢复
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {
mViewModelStore = nc.viewModelStore;
}
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
......
}
......
}
在onCreate的时候会从NonConfigurationInstances中将ViewModelStore恢复出来,这段恢复的代码是不是有点熟悉,在创建的时候getViewModelStore()方法中有一样的代码。同时在这里我们也看到了Fragment保存状态的恢复,这些Fragment保存状态中就包含了ViewModelStore,这里关于Fragment的我们稍后再看,先看Activity的。
现在我们找到了ViewModelStore在重建Activity中恢复的地方了,那就开始寻找是在哪里保存的呢。
FragmentActivity中保存
/**
* Retain all appropriate fragment state. You can NOT
* override this yourself! Use {@link #onRetainCustomNonConfigurationInstance()}
* if you want to retain your own state.
*/
@Override
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
if (fragments == null && mViewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = mViewModelStore;
nci.fragments = fragments;
return nci;
}
在这里我们看到了Activity的ViewModelStore被保存在了NonConfigurationInstances中,之前在恢复的时候我们也看到了是从NonConfigurationInstances中恢复出来的,,同时也找到了Fragment信息的保存代码,关于Fragment的同样是后面再看。这里有个小知识点,从官方注释可以知道,我们如果需要做自定义的数据保存需要重写onRetainCustomNonConfigurationInstance()而不是onRetainNonConfigurationInstance()这点要注意。
剩下的就跟Activity的启动流程有关了,这里不详细说明,就大概说一下。在ActivityThread调用performDestroyActivity()方法的时候会调用retainNonConfigurationInstances()方法将NonConfigurationInstances保存到ActivityClientRecord中,即lastNonConfigurationInstances属性上,然后在ActivityThread 调用performLaunchActivity()方法执行Activity.attach()方法的时候传递给重建的新的Activity。
Fragment保存
下面我们来看一下Fragment中是怎么保存ViewModel的。之前在看Activity的时候,我们就看到了FragmentManagerNonConfig信息保存和恢复的代码,Fragment的相关内容就在这里面。
这里我们使用反向寻找的办法,从Activity中保存的代码中向上寻找会比较简单一点。
还记得在FragmentActivity中onRetainNonConfigurationInstance()中的代码吗:
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
跟下去,在FragmentController中:
public FragmentManagerNonConfig retainNestedNonConfig() {
return mHost.mFragmentManager.retainNonConfig();
}
这里的mFragmentManager是FragmentManagerImpl,是FragmentManager的现实类。继续,FragmentManager中:
FragmentManagerNonConfig retainNonConfig() {
setRetaining(mSavedNonConfig);
return mSavedNonConfig;
}
继续下去:
private static void setRetaining(FragmentManagerNonConfig nonConfig) {
if (nonConfig == null) {
return;
}
List<Fragment> fragments = nonConfig.getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
fragment.mRetaining = true;
}
}
List<FragmentManagerNonConfig> children = nonConfig.getChildNonConfigs();
if (children != null) {
for (FragmentManagerNonConfig child : children) {
setRetaining(child);
}
}
}
这里可以看到,使用递归的方式将mSavedNonConfig其中fragment.mRetaining = true,然后将mSavedNonConfig返回。下面我们来看看mSavedNonConfig是什么,怎么来的:
// Saved FragmentManagerNonConfig during saveAllState() and cleared in noteStateNotSaved()
FragmentManagerNonConfig mSavedNonConfig;
这里官方有解释,大概意思就是在saveAllState()保存FragmentManagerNonConfig,并在noteStateNotSaved()中清除。那就很简单了,找saveAllState()方法,这个方法特别长,这里只展示跟saveNonConfig有关的部分代码:
Parcelable saveAllState() {
......
mStateSaved = true;
mSavedNonConfig = null;
......
saveNonConfig();
return fms;
}
继续看saveNonConfig()方法,这里我们就展示跟ViewModelStore有关的代码了:
void saveNonConfig() {
ArrayList<Fragment> fragments = null;
ArrayList<FragmentManagerNonConfig> childFragments = null;
ArrayList<ViewModelStore> viewModelStores = null;
if (mActive != null) {
for (int i=0; i<mActive.size(); i++) {
......
if (viewModelStores == null && f.mViewModelStore != null) {
viewModelStores = new ArrayList<>(mActive.size());
for (int j = 0; j < i; j++) {
viewModelStores.add(null);
}
}
if (viewModelStores != null) {
viewModelStores.add(f.mViewModelStore);
}
}
}
}
if (fragments == null && childFragments == null && viewModelStores == null) {
mSavedNonConfig = null;
} else {
mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments,
viewModelStores);
}
}
这里的mActive是一个SparseArray<Fragment>,for循环将其中的所有Fragment的ViewModelStore存放到ArrayList<ViewModelStore> viewModelStores,然后在实例化一个FragmentManagerNonConfig赋值给mSavedNonConfig。那么这条线就通了,Fragment的ViewModel最后是用过FragmentManagerNonConfig交给了NonConfigurationInstances进行保存的。那saveAllState()又是谁来调用的呢,是由FragmentController来管理的,在FragmentActivity调用onSaveInstanceState()方法的时候就会同时保存Fragment的状态。
Fragment恢复
还记得FragmentActivity中的恢复代码吗:
mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
这里从NonConfigurationInstances中拿到了需要恢复的FragmentManagerNonConfig调用了FragmentController的restoreAllState()方法:
public void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
mHost.mFragmentManager.restoreAllState(state, nonConfig);
}
继续,这里代码也很多,我们只看ViewModelStore相关的就行:
void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
......
List<FragmentManagerNonConfig> childNonConfigs = null;
List<ViewModelStore> viewModelStores = null;
if (nonConfig != null) {
List<Fragment> nonConfigFragments = nonConfig.getFragments();
childNonConfigs = nonConfig.getChildNonConfigs();
viewModelStores = nonConfig.getViewModelStores();
......
}
mActive = new SparseArray<>(fms.mActive.length);
for (int i=0; i<fms.mActive.length; i++) {
FragmentState fs = fms.mActive[i];
if (fs != null) {
......
ViewModelStore viewModelStore = null;
if (viewModelStores != null && i < viewModelStores.size()) {
viewModelStore = viewModelStores.get(i);
}
Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig,
viewModelStore);
......
}
}
......
}
这里还是比较好理解的,大概就是从FragmentManagerNonConfig取出保存的List<ViewModelStore>,然后循环将ViewModelStore赋值到原先对应的Fragment上。
至此Activity、Fragment创建,销毁,保存,复用ViewModel的流程就基本清楚了。