前言
我们使用mvvm框架时,ViewModel常常用来保存我们的数据,这样做的好处在于当Activity因为配置的改变(如常见的屏幕翻转)而重新创建时,我们的放在ViewModel中的数据仍然能够不被销毁。这样做的好处在于我们不必像以前在OnSaveInstanceState中保存可能因为配置改变而被销毁的变量,然后再在OnCreate中恢复数据。
本片文章我将从源码的角度分析一下Android是如何实现ViewModel在配置改变时不被重建的原理。
代码分析
下面是我们常用的创建ViewModel的方法:
SearchViewModel viewModel = new ViewModelProvider(this).get(SearchViewModel.class);
我们来看一下ViewModeProvider的构造方法:
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
可以看到需要一个实现了ViewModelStoreOwner就扣的参数,这个接口只有一个方法,用于获取ViewModelStore对象
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
从名字上可以看出ViewModelStore使用来存放ViewMode的。Activity实现了ViewModelStoreOwner,并且重写了getVeiwModelStore()的方法。我们来看一下具体实现。
@Override
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;
}
这个方法当本地变量mViewModelStore为空时,会通过getLastNonConfigurationInstance()方法尝试获得ViewModeStore,如果没有的活就重新创建。而ViewModel不被销毁的玄机就在这里。
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
NonConfigurationInstaces是个很简单的类,包含了ViweModelStore,而getLastNonConfigurationInstace会尝试获取上次配置改变被保存的NonConfigurationInstaces对象。那么在哪儿保存的呢?很快我发现了一个方法。
/**
* Retain all appropriate non-config state. You can NOT
* override this yourself! Use a {@link androidx.lifecycle.ViewModel} if you want to
* retain your own non config state.
*/
@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;
}
通过注释我们可以了解到这就是我们要找的方法。实际实现是很简单的,就是viewModeStore不为null或者lastNonConfigurationInstacne不为null时,我们就把viewModelStore保存起来。当重新创建时,我们就能从getLastNonConfigurationInstance()得到我们保存到的ViewModelStore了,而ViewModelStore里面就有我们的ViewMode。
总结
其实整体思路还是很简单的。就是要销毁前回调用onRetainNonConfigurationInstance()方法保存viewModelStore在lastNonConfigurationInstacne.activity中,然后在getViewModelStore方法中又会首先去获取lastNonConfigurationInstace.activity对象。