要理解ViewModel恢复和保存原理,首先需要看看ViewModel的使用方式
private val vm: TestVM by *viewModels*()
@MainThread
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(
noinline factoryProducer: (() -> Factory)? = null
): Lazy<VM> {
val factoryPromise = factoryProducer ?:{
defaultViewModelProviderFactory
}
return ViewModelLazy(VM::class,{viewModelStore}, factoryPromise)
}
public class ViewModelLazy<VM : ViewModel> (
private val viewModelClass: KClass<VM>,
private val storeProducer: () -> ViewModelStore,
private val factoryProducer: () -> ViewModelProvider.Factory
) : Lazy<VM> {
private var cached: VM? = null
override val value: VM
get() {
val viewModel = cached
return if (viewModel == null) {
val factory = factoryProducer()
val store = storeProducer()
ViewModelProvider(store, factory).get(viewModelClass.java).also{
cached =it
}
} else {
viewModel
}
}
override fun isInitialized(): Boolean = cached != null
}
ViewModel 由ViewModelProvider创建,来看看ViewModelProvider的构造方法
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner))
public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
owner.viewModelStore,
factory
)
ViewModelStoreOwner 是一个接口
public interface ViewModelStoreOwner {
ViewModelStore getViewModelStore();
}
ViewModelStoreOwner接口只有一个方法,getViewModelStore(),返回一个ViewModelStore,
ViewModelStore是存储缓存类
ViewModelStore负责存储ViewModel,虽然已经找到了ViewModel的缓存方式,但是ViewModelStore的存储谁负责?,要分析这个问题,就需要先分析ViewModelStoreOwner的实现类
ComponentActivity
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.");
}
ensureViewModelStore();
return mViewModelStore;
}
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
~~~~
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
当mViewModelStore等于null的时候,会先从NonConfigurationInstances获取缓存,如果获取不到,就直接创建
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
custom可以暂时不管
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
getLastNonConfigurationInstance是Activity的方法 ,mLastNonConfigurationInstances 如果不为空,就获取mLastNonConfigurationInstances.activity
mLastNonConfigurationInstances是什么?
来看Activity.java
static final class NonConfigurationInstances {
Object activity;
HashMap<String, Object> children;
FragmentManagerNonConfig fragments;
ArrayMap<String, LoaderManager> loaders;
VoiceInteractor voiceInteractor;
}
看到这里已经大概清楚了,ComponentActivity.NonConfigurationInstances 保存ViewModelStore ,而Activity.NonConfigurationInstances 保存ComponentActivity.NonConfigurationInstances ,那触发保存的方法是什么?
通过代码引用发现Activity.NonConfigurationInstances 被引用在ActivityClientRecord.lastNonConfigurationInstances字段中
![ActivityClientRecord 具体是什么,我们这里先不管,找到这里还还不能知道具体保存的问题,继续查看引用,在performDestroyActivity中对NonConfigurationInstances#lastNonConfigurationInstances赋值了 ,知道Activity的启动原理的同学应该都知道它是干嘛的,后面我也会写一篇文章来分析其具体源码
ActivityClientRecord 具体是什么,我们这里先不管,找到这里还还不能知道具体保存的问题,继续查看引用,在performDestroyActivity中对NonConfigurationInstances#lastNonConfigurationInstances赋值了 ,知道Activity的启动原理的同学应该都知道它是干嘛的,后面我也会写一篇文章来分析其具体源码 这里来分析下这个方法,我删除了其他无用代码
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
public static final class ActivityClientRecord {
Activity.NonConfigurationInstances lastNonConfigurationInstances;
...
}
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
int configChanges, boolean getNonConfigInstance, String reason) {
...
//如果getNonConfigInstance为true,就对lastNonConfigurationInstances重新赋值
ActivityClientRecord r = mActivities.get(token);
if (getNonConfigInstance) {
r.lastNonConfigurationInstances
= r.activity.retainNonConfigurationInstances()
}
...
//既然保存了,为什么这里却移除了?
mActivities.remove(token);
}
问题:
1.getNonConfigInstance 什么时候true?
2.mActivities移除了当前Activity的ActivityClientRecord,那Activity#NonConfigurationInstances到底是怎么被保存下来的?
3.retainNonConfigurationInstances()是干什么?
先看看问题3
Activity#retainNonConfigurationInstances
NonConfigurationInstances retainNonConfigurationInstances() {
Object activity = onRetainNonConfigurationInstance();
...
if (activity == null && children == null && fragments == null && loaders == null
&& mVoiceInteractor == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity;
...
return nci;
}
onRetainNonConfigurationInstance如果是null,直接返回null,否则赋值到新建的NonConfigurationInstances中并返回
Activity#onRetainNonConfigurationInstance
public Object onRetainNonConfigurationInstance() {
return null;
}
Activity#onRetainNonConfigurationInstance并没有返回具体的值,来看ComponentActivity #onRetainNonConfigurationInstance
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;
}
onRetainNonConfigurationInstance是final的,被不能被重写,这个方法比较简单就是对viewModelStore重新存储在NonConfigurationInstances
再找到performDestroyActivity的引用链,handleRelaunchActivityInner→handleDestroyActivity →performDestroyActivity
private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
PendingTransactionActions pendingActions, boolean startsNotResumed,
Configuration overrideConfig, String reason) {
final Intent customIntent = r.activity.mIntent;
if (!r.paused) {
performPauseActivity(r, false, reason, null );
}
if (!r.stopped) {
callActivityOnStop(r, true , reason);
}
handleDestroyActivity(r.token, false, configChanges, true, reason);
...
handleLaunchActivity(r, pendingActions, customIntent);
}
说明:handleRelaunchActivityInner在重新启动Activity调用
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
...
final Activity a = performLaunchActivity(r, customIntent);
...
return a;
}
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,
r.assistToken);
...
return activity;
}
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, IBinder assistToken) {
...
mLastNonConfigurationInstances = lastNonConfigurationInstances;
...
}
handleLaunchActivity→performLaunchActivity→attach,通过引用链发现 NonConfigurationInstances最终被传入到Activity#attach方法中,对mLastNonConfigurationInstances重新赋值
总结:
1.ViewModel的保存只会在重启当前Activity才会调用
2.ViewModel存储在ViewModelStore里
3.ViewModelStore在Activity#attach中赋值
|