ViewModel 数据保存和恢复原理源码分析过程

要理解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()
								//这里就是创建ViewModel的地方
                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 children;
    FragmentManagerNonConfig fragments;
    ArrayMap loaders;
    VoiceInteractor voiceInteractor;
}

看到这里已经大概清楚了,ComponentActivity.NonConfigurationInstances保存ViewModelStore,而Activity.NonConfigurationInstances 保存ComponentActivity.NonConfigurationInstances,那触发保存的方法是什么?

通过代码引用发现Activity.NonConfigurationInstances被引用在ActivityClientRecord.lastNonConfigurationInstances字段中
ViewModel 数据保存和恢复原理源码分析过程_第1张图片

![ActivityClientRecord具体是什么,我们这里先不管,找到这里还还不能知道具体保存的问题,继续查看引用,在performDestroyActivity中对NonConfigurationInstances#lastNonConfigurationInstances赋值了,知道Activity的启动原理的同学应该都知道它是干嘛的,后面我也会写一篇文章来分析其具体源码
ViewModel 数据保存和恢复原理源码分析过程_第2张图片

ActivityClientRecord具体是什么,我们这里先不管,找到这里还还不能知道具体保存的问题,继续查看引用,在performDestroyActivity中对NonConfigurationInstances#lastNonConfigurationInstances赋值了,知道Activity的启动原理的同学应该都知道它是干嘛的,后面我也会写一篇文章来分析其具体源码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aYoNfV8P-1644070820874)(ViewModel%20%E6%95%B0%E6%8D%AE%E4%BF%9D%E5%AD%98%E5%92%8C%E6%81%A2%E5%A4%8D%E5%8E%9F%E7%90%86%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E8%BF%87%E7%A8%8B%2001cc0e78a27348f080017ed08dc85082/Untitled%201.png)]

这里来分析下这个方法,我删除了其他无用代码

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() {
    // Maintain backward compatibility.
    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 /* pendingActions */);
    }
    if (!r.stopped) {
        callActivityOnStop(r, true /* saveState */, reason);
    }
		//这里对getNonConfigInstance赋值为true
    handleDestroyActivity(r.token, false, configChanges, true, reason);

   ...
		//问题2 在这里也清楚了,虽然ActivityClientRecord被移除了,但是又传入了handleLaunchActivity
    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中赋值

你可能感兴趣的:(Android,kotlin,android,jetpack)