开始的时候我们先想三个问题
1.ViewModel是怎么创建的
2.ViewModel的存储方式是什么,他是怎么和LifecycleOnwer绑定的
3.如果ViewModel的生命周期和LifecycleOnwer绑定,为什么ViewModel在屏幕旋转这种Activity销毁重建的情况下,能继续持有数据
1.ViewModel是怎么创建的
一般情况下,我们获取某个viewModel的时候,是调用以下方法获取
scss
val viewModel = ViewModelProvider(lifecycleOwner, viewModelFactory).get(viewModelClass)
这里的话是创建一个ViewModelProvider对象,构造函数传入lifecycleOwner, viewModelFactory,然后通过viewModelClass这个key去获取对应的viewModel。(其实这里隐约可以猜出,底层应该是类似于map的方式,viewModelClass为key,viewModel对象为value)
点进ViewModelProvider的这个构造方法,可以看到它实际调用的是另一个构造方法 this(owner.getViewModelStore(), factory),注意这里ViewModelStore是通过owner去获取的,那这里的ViewModelStore和Factory就是ViewModelProvider的关键成员了。
less
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
接下来我们再看看get方法,可以看到最终还是调了另外一个get的重载方法get(@NonNull String key, @NonNull Class modelClass),传入了DEFAULT_KEY + ":" + canonicalName(class的一个方法,获取类的规范化名称)作为key。
然后真正的get方法里,通过这个key,从mViewModelStore获取viewmodel,如果为null,则通过Factory新建一个。
less
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@SuppressWarnings("unchecked")
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
// 注释1 通过key获取viewmodel
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
ViewModelStore
从刚才的代码中,我们可以看到ViewModelStore是一个key value形式保存的数据结构,那接下来我们看看ViewModelStore的源码是怎么实现的。
typescript
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
可以看到核心就是一个HashMap,在这基础知识,新增了clear的方法。
Factory
less
public interface Factory {
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
可以看到Factory其实就是一个接口,具体的create方法需要自己实现,这里我们看一下NewInstanceFactory的默认实现。
typescript
public static class NewInstanceFactory implements Factory {
private static NewInstanceFactory sInstance;
/**
* Retrieve a singleton instance of NewInstanceFactory.
*
* @return A valid {@link NewInstanceFactory}
*/
@NonNull
static NewInstanceFactory getInstance() {
if (sInstance == null) {
sInstance = new NewInstanceFactory();
}
return sInstance;
}
@SuppressWarnings("ClassNewInstance")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
}
可以看到是通过反射的方式,new出了一个实例。
那这样的话,前面提到的两个问题的答案就很明显了
1.ViewModel是怎么创建的
ViewModel是通过ViewModelProvider获取的,它的创建则是通过传入的Factory.create进行创建,默认的实现NewInstanceFactory是直接通过反射的方式new出了viewmodel的实例。
2.ViewModel的存储方式是什么,他是怎么和LifecycleOnwer绑定的
ViewModel是存储在ViewModelStore里的,ViewModelStore底层是一个HashMap,value的值就是ViewModel,而key值则是DEFAULT_KEY + ":" + canonicalName。
他是怎么和LifecycleOnwer绑定的呢,在ComponentActivity的构造函数里,添加了一个lifecycle的观察者,在lifecycle生命周期变为ON_DESTROY的时候,且不是isChangingConfigurations的时候,清除这个ViewModelStore。
less
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
从上面的结论中我们可以得出第三个问题的答案,在满足不是isChangingConfigurations的时候,ViewModel就算在Activity销毁后,也不会clear。这个isChangingConfigurations是Activity的一个成员变量,其含义是用于判断当前 Activity 是否因为配置变更而被系统销毁并重建。
那这样的话还有个额外的问题就是,Activity重建了肯定会重新创建一个实例,那此时ViewModel存在哪里呢。
less
@NonNull
@Override
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;
}
通过getViewModelStore可以知道,ViewModelStore是通过一个叫NonConfigurationInstances的东西来获取的,那我们继续看看NonConfigurationInstances是哪来的。
arduino
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) {
attachBaseContext(context);
// 省略
mLastNonConfigurationInstances = lastNonConfigurationInstances;
// 省略
}
通过mLastNonConfigurationInstances赋值的地方我们可以看到,他是在Activity.attach里被复制的,那这个Activity.attach是什么时候被调用的呢。他其实是在ActivityThread里的performLaunchActivity被调用的,如果看过startActivity的源码应该对这个方法不陌生。
typescript
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);
// 省略
return activity;
}
可以看到这个lastNonConfigurationInstances是被ActivityClientRecord所持有的,那这个ActivityClientRecord是存在ActivityThread里用于跟踪和管理Activity运行时状态的地方,每个运行的 Activity 都对应一个 ActivityClientRecord实例
ini
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
这下我们就明白了ActivityThread通过存储ActivityClientRecord.mLastNonConfigurationInstances 从而帮Activity存储了他所需要的ViewModelStore,这样不管这个Activity怎么销毁重建,只要ActivityThread还在记录他的状态,那ViewModelStore就不会被销毁,这样在重建后也可以马上拿到ViewModelStore还原数据。