viewmodel的存取流程


一:获取view model的代码

public extends ViewModel> T get(@NonNull String key, @NonNull Class modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);//从一个hash map中用key取view model,key是view model的类名。

        if (modelClass.isInstance(viewModel)) {//如果还没有view model实例,即上一步得到null, 那么就不会进去,如果进入了,就会返回view mdoel了
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel; //返回view model
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);//创建view model
        } else {
            viewModel = mFactory.create(modelClass);//创建view model
        }
        mViewModelStore.put(key, viewModel);//往map里面插入这个view model
        return (T) viewModel;
    }

activity实现了view model store owner,拥有view model store,view model store则拥有一个map存放view model。

但是当配置更改时,view model store实例如何才能保证是旧的那个呢?

二:如何不改变view model store

首先来看看activity如何获取view model store

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创建时view model store都是null,当我们第一次取时,会看看nc,如果nc不为null,代表nc存有以前的view model,就取出来就行了,没有就创建。

所以关键是,这个nc是什么,它是如何保存我们之前的viewmodel的,为森马它不为空,就存有旧 viewmodel呢?

搞明白这个nc,就知道view mdoel store是如何不变的了。

三:搞明白NonCon.....Instances如何存

在上一段代码中,ComponenetActivity.java的getViewModelStore方法会调用Activity.java的getLastNCI方法,getLastNCI方法会返回Activity.java内部的一个NCI对象

static final class NonConfigurationInstances {
        Object activity;
        。。。。。
    }

那为什么这个对象会存有我们的viewmdoelstore实例呢?

原因就是:

当Activity.java销毁的时候,会保存Activity.NCI实例:

Activity,java

NonConfigurationInstances retainNonConfigurationInstances() {
        Object activity = onRetainNonConfigurationInstance();
       ......

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.activity = activity;
      
        return nci;
    }


ComponentActivity.java

public final Object onRetainNonConfigurationInstance() {
       
        ViewModelStore viewModelStore = mViewModelStore;
       ......
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.viewModelStore = viewModelStore;
        return nci;
}

activity销毁的时候,系统会调用retainXXXX,然后调用 onRetainXXXX,把view model store存进去了,把ComponentActivity.java的NCI对象存到Activity.java的NCI对象的一个叫做“activity”的变量里面,这个变量名十分误导人,叫其他不好吗?叫store也好啊!!

四:搞明白NonCon.....Instances如何恢复

系统调用Activity.java的attach方法

Activity.java

final void attach( NonConfigurationInstances lastNonConfigurationInstances){

...
mLastNonConfigurationInstances = lastNonConfigurationInstances
...
}

这样呢,在第二部分 ComponentActivity.java获取viewmdoelstore的方法里就可以获取到这个NCI了。

整体流程如下

参考:https://blog.mindorks.com/android-viewmodels-under-the-hood