我们都知道在配置更改期间,Activity或Fragment会进行重建,但ViewModel中的数据去不会丢失,还是会保留上次的数据。那么问题来了这是怎么实现的了?
我们可以先来回忆一下我们是怎么创建ViewModel的:
CategoriesViewModel mViewModel = new ViewModelProvider(this).get(CategoriesViewModel.class);
我们一般是 ViewModelProvider来创造的,this可以为Activity和Fragment的上下文。那么这个方法有什么问题呢?我们来看下ViewModelProvider的构造方法。
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
可以看到这里通过owner.getViewModelStore()来得到ViewModelStore。当owner是Activity时,我们可以在Acitivity的子类ComponentActivity中找到这个方法的实现:
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
HasDefaultViewModelProviderFactory,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
// Lazily recreated from NonConfigurationInstances by getViewModelStore()
private ViewModelStore mViewModelStore;
@NonNull
@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;
}
}
在ComponentActivity中有一个ViewModelStore的参数,这个类是用来存储ViewModel的。接着我们看下getViewModelStore的方法,其中的getLastNonConfigurationInstance()其实是用来获取当活动由于一些配置改变而重建时保存下来的数据。ComponentActivity中的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;
看到了吗?这里很清楚的可以发现它保存了自己的viewModelStore参数。这样就能使即使活动重建了,活动中的viewModelStore仍然会是重建前的那一个。
现在我们已经知道了在活动重建时其里面的viewModelStore变量并不会改变。我们回到最初创造ViewModelProvider的方法中:
//ViewModelProvider
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
现在就可以很容易知道了,当我们创建ViewModelProvider时,会直接将传入的ViewModelStoreOwner(Activity,Fragment都有继承ViewModelStoreOwner的接口)的viewModelStoreOwner赋值给ViewModelProvider中的mViewModelStore。然后再调用其中的get
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)) {
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;
}
get方法会从mViweModelStore中寻找是否已经有存在的ViewModel否则就会直接创造一个然后再存入mViewModelStore;
总结
Activity重建时会保存自己的ViewModelStore的数据,ViewModelStore中有所有的以当前Activity为参数创建的ViewModel对象。而ViweModelProvider中初始化后会持有Activity中viewModelStore的引用,于是就会得到销毁前的ViewModel对象。