众所周知,ViewModel可以在界面销毁重建后仍然保存之前的数据,而到底是怎么在界面销毁重建期间进行保存的呢,本篇文章就就该问题进行一个探究。
由于ViewModel
能够在界面销毁重建时保存数据,那我们就从Activity
销毁的时机作为入口一探究竟。
AMS
通知ApplicationThread
执行界面销毁应用执行界面销毁是通过AMS
通过Binder
跨进程通知应用这边的ApplicationThread
这个Binder对象,而ApplicationThread
通过Handler
最终会执行到ActivityThread.handleDestroyActivity()
方法。
而这个方法又会调用performDestroyActivity()
方法,我们看下源码:
Activity.retainNonConfigurationInstances()
瞧一瞧NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
//...
return nci;
}
紧接着就会调用onRetainNonConfigurationInstance()
方法,ComponentActivity
会对这个方法进行重写:
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
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;
}
这个方法值得细细分析一下,首先先搞清楚mViewModelStore
是个啥:
看到这里是不是明白了:mViewModelStore
是个ViewModelStore
类型,而我们在Activity界面创建的ViewModel就会保存到这个对象之中
。
到了这里,我们就可以知道:ActivityThread.handleDestroyActivity()
最终会一步步走到mViewModelStore
,将其进行保存。
接下来我们就看下这个值mViewModelStore
经过一步步调用是怎么保存的 。
mViewModelStore
如何一步步调用保存?回到我们的方法onRetainNonConfigurationInstance()
中,从源码中可以看到,mViewModelStore
最终会保存到ComponentActivity$NonConfigurationInstances
类的viewModelStore
成员属性中,并返回ComponentActivity$NonConfigurationInstances
对象。
简单看下NonConfigurationInstances
类结构:
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
我们跳到调用onRetainNonConfigurationInstance()
方法的Activity.retainNonConfigurationInstances()
方法中:
可以看到上面的onRetainNonConfigurationInstance()
方法返回的ComponentActivity$NonConfigurationInstances
对象最终会保存到Activity$NonConfigurationInstances
类的activity
成员变量中。
请注意,别搞混了NonConfigurationInstances
类,Acitivity
和ComponentActivity
都有定义这个类,我们看下Acitivity
定义的NonConfigurationInstances
结构:
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
最终Activity.retainNonConfigurationInstances()
方法会将Activity$NonConfigurationInstances
类对象返回到上一层。
最终我们又回到了performDestroyActivity()
方法中:
最终Activity$NonConfigurationInstances
会保存到ActivityClientRecord
的lastNonConfigurationInstances
属性中。
而这个ActivityClientRecord
是保存到ActivityThread
的mActivities
集合中,其中key就是token
,value就是为ActivityClientRecord
。
界面重新创建销毁后,AMS会通知ApplicationThread
最终调用到performLaunchActivity()
方法。
这个方法就是用来创建Activity
的,创建完毕后就会调用我们熟悉的Activity.attach()
方法:
可以看到这个方法传递的参数其中之一就是ActivityClientRecord
的lastNonConfigurationInstances
属性,继续深入看下Activity.attach()
方法:
final void attach(//...NonConfigurationInstances lastNonConfigurationInstances,//...) {
attachBaseContext(context);
//...
mLastNonConfigurationInstances = lastNonConfigurationInstances;
//...
}
最终这个lastNonConfigurationInstances
会赋值给Acitivty
的mLastNonConfigurationInstances
属性。
而mLastNonConfigurationInstances
就是Activity$NonConfigurationInstances
对象,就保存了之前存储ViewModel
的ViewModelStore
,这就间接实现了保存了ViewModel
中持有的数据。
ViewModel
的获取流程我们看下如何在Activity
中创建一个ViewModel
:
private val mViewModel: MainViewModel by viewModels()
关键就是viewModels()
方法:
最终ViewModel
会尝试从viewModelStore
中获取,获取不到通过反射创建。而viewModelStore
是从哪里来的呢?
可以看到,最终这个viewModelStore
最终就是从上面的Activity.mLastNonConfigurationInstances
属性中获取。
本篇文章我们详细分析ViewModel
如何实现在Activity
界面销毁重建后还能够保存销毁前的数据的,希望对你有所帮助。
阅读量:1075
点赞量:0
收藏量:0