ViewModel是什么?ViewModel是负责管理Activity和Fragment的数据的类,他独立于Activity和Fragment之外,即使Activity和Fragment因为屏幕旋转等原因销毁,只要Activity与Fragment重新创建,即可与原先的ViewModel重新绑定。首先查看ViewModel的获取方式:
val viewModel = ViewModelProviders.of(target, factory).get(PlanViewModel::class.java)
ViewModelProviders.of()方法获取ViewModelProvider的实例,然后通过get()方法获取ViewModel,ViewModelProvider.get()实现如下:
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;
}
ViewModelProvider.get(key, class)方法,先查询要获取的viewmodel实例是否已经在ViewModelStroe中,如果实例已经存在于ViewModelStore中,则返回之前的实例,否则通过ViewModelProvider.Factory创建一个viewModel实例,并存放于viewModel中,下次再获取该类型的viewModel时,只要是同一个ViewModelStroe,就可以将缓存的viewModel返回。那么如何保证即使Activity重新创建后,获取到viewModel还是之前的ViewModel呢?由于ViewModelStroe内部仅仅是通过Map去管理ViewModel的缓存,所以只有保证Activity销毁重建后,ViewModelStroe是同一个,即可保证拿到的是原来的ViewModel。ViewModelStroe是从哪里来的呢?
继续看ViewModelProviders.of()的实现:
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(fragment.getViewModelStore(), 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(activity.getViewModelStore(), factory);
}
通过of方法的实现可以看到ViewModelStore由实现了ViewModelStoreOwner的Activity和Fragment提供,下面分2部分分别去查看Activity和Fragment的实现;
Activity是如何管理ViewModelStore的
Activity都重新创建了,activity是如何保证ViewModelStore还是原来的呢?
下面看Activity.getViewModelStroe的实现:
ComponentActivity.java
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;
}
Activity通过NonConfigurationInstances 实现对ViewModelStore的管理,显示获取最后的NonConfigurationInstances 实例,然后将NonConfigurationInstances.viewModelStore赋值给自己,这个NonConfigurationInstances.viewModelStore就是Activity销毁重建前的ViewModelStore
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
到这里又看到一个NonConfigurationInstances,这里有点迷惑性,getViewModelStore里的NonConfigurationInstances是ComponentActivity.NonConfigurationInstances,getLastNonConfigurationInstance里的是Activity.NonConfigurationInstances,ComponentActivity.NonConfigurationInstances管理ViewModelStore,而Activity.NonConfigurationInstances则管理ComponentActivity.NonConfigurationInstances。接下来继续看getLastNonConfigurationInstance(),这个mLastNonConfigurationInstances 是在哪里创建的呢?是在activity.attach()里作为参数从外界传入的。activity.attch()则是在ActivityThread.performLaunchActivity()里被调用。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
return activity;
}
继续追踪到ActivityThread.performLaunchActivity,可以看到,Activity.lastNonConfigurationInstances来源于ActivityClientRecord.lastNonConfigurationInstances,那么ActivityClientRecord.lastNonConfigurationInstances是什么时候被赋值的呢?答案是在activity销毁的时候,我们继续看ActivityThread.performDestroyActivity():
ActivityThread.performDestroyActivity() {
if (getNonConfigInstance) {
try {
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);
}
}
}
}
在ActivityThread.performDestroyActivity() 中将Activity.retainNonConfigurationInstances()返回值赋给ActivityClientRecord.lastNonConfigurationInstances,继续看Activity.retainNonConfigurationInstances():
NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
//获取Fragment的mNonConfig快照信息,用于重新恢复Fragment
FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();
// We're already stopped but we've been asked to retain.
// Our fragments are taken care of but we need to mark the loaders for retention.
// In order to do this correctly we need to restart the loaders first before
// handing them off to the next activity.
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;
}
在retainNonConfigurationInstances()中,会创建返回一个Activity.NonConfigurationInstance实例,并且在里边看到熟悉的代码:
Object activity = onRetainNonConfigurationInstance();
nci.activity = activity;
再回到getLastNonConfigurationInstance()方法中,
return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null;
由此我们知道onRetainNonConfigurationInstance()返回的是管理ViewModelStore的ComponentActivity.NonConfigurationInstance对象,接着看其实现:
@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;
}
onRetainNonConfigurationInstance()创建了一个持有ViewModelStroe的ComponentActivity.NonConfigurationInstance对象,到此我们追踪了一遍Activity销毁重新创建,而ViewModel保持不变的流程。总结下:
1、Activity销毁时,通过Activity.retainNonConfigurationInstances()创建Activity.NonConfigurationInstace对象交给ActivityClientRcord保存,而Activity.NoConfigurationInstance.activity持有ComponentActivity.NonConfigurationInstance对象,ComponentActivity.NonConfigurationInstance则持有了ViewModelStore
2、Activity创建后,在Activity.attch()中,将ActivityClientRcord持有的Activity.NonConfigurationInstace对象赋值给Activity.mLastNonConfigurationInstances
3、当调用ViewModelProviders.of()的时候,会调用ComponentActivity.getViewModelStore(),在getViewModelStore()中,会通过2的mLastNonConfigurationInstances获取到ComponentActivity.NonConfigurationInstance对象,并将ComponentActivity.NonConfigurationInstance持有的ViewModelStore返回。
这样就保证了Activity销毁重新创建,而ViewModelStore还是那个销毁前的ViewModelStore,所以我们通过
ViewModelProviders.of(target, factory).get(ViewModel.class)
获取到的也还是Activity销毁前的那个ViewModel.
Fragment如何管理ViewModelStore
Fragment.getViewModelStore()实现如下:
public ViewModelStore getViewModelStore() {
if (mFragmentManager == null) {
throw new IllegalStateException("Can't access ViewModels from detached fragment");
}
return mFragmentManager.getViewModelStore(this);
}
fragment自己并不直接管理ViewModel,通过代理FragmentManager.getViewModel()返回ViewModel,接下去再看FragmentManger.getViewModel的实现:FragmentManagerImpl.getViewModel()
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
FragmentManagerImpl又通过mNonConfig去管理ViewModelStore,我们看看mNonConfig时在什么时候创建的:
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) {
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false);
}
}
根据Fragment是否是子Fragment,以及Activity是否实现了ViewModelStoreOwner分为3中情况:
1、Fragment根Fragment且Activity实现了ViewModelStoreOwner接口时,从Activity.getViewModelStore获取viewModelStore,根据我们上面的分析可以知道这个viewModelStore是销毁重新创建前的viewModelStore,由于mNonConfig是个ViewModel,所以通过viewModelStore获取到的mNonConfig也是销毁重建前的mNonCofig。
2、fragment是子fragment时,mNonConfig从父Fragment的mNonConfig中获取,如果activity实现了ViewModelStoreOwner,则回到1,mNonCofig还是销毁前的那个mNonCofig;如果activity没有实现ViewModelStoreOwner,则回到3.
3.如果Activity没有实现ViewModelStoreOwner时,则从新创建一个全新的mNonConfig.
由于mNonConfig是销毁之前的mNonConfig,则通过mNonConfig管理的ViewModelStore也自然是销毁前的ViewModelStore。由此可见保证fragment的viewModeStore时销毁之前的ViewModelStore,是依赖于Activity的实现的。