打开官网,咱们能够看到 ViewModel 的描述:html
The
ViewModel
class allows data to survive configuration changes such as screen rotations.java
同时还给出了 ViewModel 的生命周期图:
android
在发生屏幕旋转时,ViewModel 实例依然存在
,为了验证这句话,我写了一个小 demo 来佐证,示例 demo 以下:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mainViewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
Log.e("TAG", "onCreate:$mainViewModel")
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
Log.e("TAG", "onSaveInstanceState:")
}
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
super.onRestoreInstanceState(savedInstanceState)
Log.e("TAG", "onRestoreInstanceState:")
}
复制代码
操做步骤很简单,就是操做屏幕旋转,佐证下 ViewModel 实例是否还是 Activity 旋转屏幕以前的实例,打印结果以下:app
2019-08-13 21:45:55.381 E/TAG: onCreate:com.codelang.jetpack.MainViewModel@b02354
2019-08-13 21:46:06.435 E/TAG: onSaveInstanceState:
2019-08-13 21:46:06.608 E/TAG: onCreate:com.codelang.jetpack.MainViewModel@b02354
2019-08-13 21:46:06.617 E/TAG: onRestoreInstanceState:
复制代码
经过日志咱们能够看到,在发生屏幕旋转时,旋转以前的 MainViewModel
与旋转后的 MainViewModel
内存地址一致,验证了官网对 ViewModel 描述的正确性。ide
咱们知道,在屏幕发生旋转时,整个 Activity 都会被销毁和重建,与之所对应的对象和变量也都会被从新初始化,但 ViewModel 的实例并无受之影响,重建以后还是以前的实例,难道 ViewModel 实例被 Activity 以外的某个变量持有?带着这样的疑问咱们来跟踪 ViewModel 的源码,看看是如何作到这点的。this
咱们来看下 ViewModel 对象的初始化:google
val mainViewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)spa
一、跟踪 ViewModelProviders.of日志
public static ViewModelProvider of(@NonNull FragmentActivity activity,@Nullable Factory factory) {
Application application = checkApplication(activity);
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
// 关键点:activity.getViewModelStore()
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
复制代码
默认会初始化一个 factory,该 factory 是一个反射初始化 MainViewModel::class.java
的工厂类,关键点咱们稍后再说,ViewModelProvider 的初始化须要传入 activity 的 ViewModelStore 和 factory。code
二、跟踪 get(MainViewModel::class.java)
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
...
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)) {
//noinspection unchecked
return (T) viewModel;
}
...
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
//三、
viewModel = (mFactory).create(modelClass);
}
//四、
mViewModelStore.put(key, viewModel);
//五、
return (T) viewModel;
}
复制代码
序列号解释:
从整个过程来看,ViewModelStore 这个对象很是重要,ViewModel 的存储与获取都与和他有关,Activity 销毁重建也是从 ViewModelStore 中获取 ViewModel 的实例,而且这个实例一直是同一个对象。
一、咱们来讲说关键点: activity.getViewModelStore()
FragmentActivity.class
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
FragmentManagerNonConfig fragments;
}
public ViewModelStore getViewModelStore() {
//一、
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;
}
复制代码
序列号解释:
二、咱们来看下 getLastNonConfigurationInstance 是如何拿到 FragmentActivity.NonConfigurationInstances
Activity.class
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
复制代码
mLastNonConfigurationInstances 是 Activity 的一个叫 NonConfigurationInstances 的静态内部类。
三、咱们来看下 mLastNonConfigurationInstances 是如何初始化的
Activity.class
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback) {
...
mLastNonConfigurationInstances = lastNonConfigurationInstances;
...
}
复制代码
在 Activity attach 的时候被外部传入进来,那么,是谁触发的 attach 呢?咱们知道,Activity 的整个建立都是 ActivityThread 来操做的。
四、咱们来看下 ActivityThread
咱们找到触发 Activity.attach() 的地方
ActivityThread.class
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
...
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);
...
mActivities.put(r.token, r);
...
}
复制代码
咱们注意到 r.lastNonConfigurationInstances
这个对象,这个对象是从 ActivityClientRecord
中取出来的,而且又将 ActivityClientRecord
存储到了 ActivityThread
的全局变量 mActivities
中。
五、咱们来看看 ActivityClientRecord 是怎么来的
下面简洁下调用链:
performLaunchActivity -> handleLaunchActivity -> handleRelaunchActivityInner -> handleRelaunchActivity
最终走到了 handleRelaunchActivity 方法:
@Override
public void handleRelaunchActivity(ActivityClientRecord tmp, PendingTransactionActions pendingActions) {
...
//一、经过 Activity 的 token 获取对应的 ActivityClientRecord
ActivityClientRecord r = mActivities.get(tmp.token);
...
handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
...
}
复制代码
最终,咱们找到了 ActivityClientRecord 的来源,所以,整个获取 ViewModelStore 的调用链就出来了:
咱们再回到 Activity 的 getViewModelStore 方法,只有在 ViewModelStore 为空的状况下才会走这个调用链,这么作的目的是为了不频繁走调用链才能拿到 ViewModel 的问题,但重建后,ViewModelStore 确定是为空的,因此,确定是有一个地方只取一次调用链拿到 ViewModelStore 对象,结果就是在 onCreate 方法中
FragmentActivity.class
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NonConfigurationInstances nc =
// 拿到调用链的 ViewModelStore 对象
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null && nc.viewModelStore != null && mViewModelStore == null) {
mViewModelStore = nc.viewModelStore;
}
...
复制代码
既然有获取,那必然就会有存储的过程,获取的源头是在 ActivityThread 的 mActivities
中,那存储必然也是在 mActivities
中。
经过 mActivities.get
的方式,在 ActivityThread 中查找相关引用:
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance, String reason) {
ActivityClientRecord r = mActivities.get(token);
...
if (getNonConfigInstance) {
try {
// 一、
r.lastNonConfigurationInstances
// 二、
= r.activity.retainNonConfigurationInstances();
} catch (Exception e) {
...
}
}
...
复制代码
序列号解释:
仔细看方法,原来是 performDestroyActivity
,也就是说,在重建 Activity 前,会将 ViewModelStore 给保存起来给 ActivityClientRecord,ActivityClientRecord 是存放在 ActivityThread 的全局 mActivities 集合中的,等到重建后,再从 mActivities 中取出 ActivityClientRecord,再把 ViewModelStore 经过 Activity 的 attach 方法再传入,这也印证了咱们的 demo 和官方的示例图,不过咱们仍是得来看看 r.activity.retainNonConfigurationInstances();
是怎么存储起来的
一、activity.retainNonConfigurationInstances
Activity.class
NonConfigurationInstances retainNonConfigurationInstances() {
//一、
Object activity = onRetainNonConfigurationInstance();
HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
...
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
...
return nci;
}
复制代码
retainNonConfigurationInstances 是一个建立 Activity.NonConfigurationInstances 的过程,根据上述调用链图可知,Activity.NonConfigurationInstances 会引用 FragmentActivity.NonConfigurationInstances 对象,引用部分在序列号 1 处 onRetainNonConfigurationInstance 方法
二、onRetainNonConfigurationInstance
FragmentActivity.class
@Override
public final Object onRetainNonConfigurationInstance() {
...
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
// 一、
nci.viewModelStore = mViewModelStore;
nci.fragments = fragments;
return nci;
}
复制代码
到这里就很清楚了,FragmentActivity.NonConfigurationInstances 会持有 mViewModelStore 对象进行存储。
咱们来更改下官方的示例图: