八股一图流
一图流
优点
-
当横竖屏发生切换时,activity会重建,但是ViewModel不需要重建。
-
ViewModel可以避免内存泄漏问题,Activity destroy时会调用ViewModel的onCleared()方法。
-
可以解决同一个Activity的不同Fragment的数据共享问题。
ViewModel如何监听生命周期
- 在Activity的父类ComponentActivity构造方法中添加了一个Lifecycle的事件监听器
- onDestroy中会分发一个名为Lifecycle.Event.ON_DESTROY的事件。
- 当我们接收到这个事件后,就会判断我们的Activity是正常销毁还是因为配置文件而销毁。
- 正常销毁的话,清除掉ViewModelStore中的数据
- 配置文件修改,保存ViewModelStore中的数据
ViewModel的恢复流程
- 会把ViewModelStore这个对象保存在ComponentActivity的静态内部类中,不受Activity重建的影响
- 配置信息发生改变后,在Activity销毁前将ViewModelStore保存,在Activity重建后将ViewModelStore恢复。
ViewModel是单向绑定还是双向绑定?
- 通常是单向绑定。持有了Model,将Model显示在View上,单向绑定View。
- 在典型的架构中,ViewModel作为视图和数据模型之间的中介层,负责提供数据给视图展示,并接收来自视图的用户操作或事件。视图可以观察(订阅)ViewModel中的数据,以便及时更新UI,但通常无法直接修改ViewModel中的数据。
流程图
保存流程图
恢复流程图
获取流程图
看看ViewModel 类的代码
public abstract class ViewModel {
// Can't use ConcurrentHashMap, because it can lose values on old apis (see b/37042460)
@Nullable
private final Map<String, Object> mBagOfTags = new HashMap<>();
private volatile boolean mCleared = false;
//在ViewModel将 被清除时调用
//当ViewModel观察了一些数据,可以在这里做解注册 防止内存泄漏
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
@MainThread
final void clear() {
mCleared = true;
if (mBagOfTags != null) {
synchronized (mBagOfTags) {
for (Object value : mBagOfTags.values()) {
// see comment for the similar call in setTagIfAbsent
closeWithRuntimeException(value);
}
}
}
onCleared();
}
.......
}
ViewModel类是抽象类,clear()方法会在ViewModel将被清除时调用。ViewModel实例获取是通过ViewModelProvider类。
//ViewModelProvider
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
ViewModelStoreOwner----ViewModel存储器持有者;
ViewModelStoreOwner的实现类有Activity/Fragment.
public interface ViewModelStoreOwner {
//获取ViewModelStore,即获取ViewModel存储器
ViewModelStore getViewModelStore();
}
ViewModelStore----ViewModel存储器,用来存储ViewModel
接下来看看ViewModelStore如何存储ViewModel以及ViewModel实例的获取
/**
* 用于存储ViewModels.
* ViewModelStore实例 必须要能 在系统配置改变后 依然存在。
*/
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());
}
/**
* 调用ViewModel的clear()方法,然后清除ViewModel
* 如果ViewModelStore的拥有者(Activity/Fragment)销毁后不会重建,那么就需要调用此方法
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
Factory----创建ViewModel实例的工厂
再看看ViewModel实例的工厂Factory—NewInstanceFactory:
public static class NewInstanceFactory implements Factory {
...
@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);
}
}
}
ViewModelProvider–创建和获取 ViewModel 对象
最后使用ViewModelProvider().get(xxx.class)来获取自定义的ViewModel实例
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");
//拿到Key,也即是 ViewModelStore中的Map的用于存 ViewModel的 Key
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//从ViewModelStore获取ViewModel实例
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
//如果从ViewModelStore中获取到,直接返回
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
//没有获取到,就使用Factory创建
viewModel = (mFactory).create(modelClass);
}
//存入ViewModelStore 然后返回
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
以上逻辑:
先尝试从ViewModelStore中获取ViewModel实例。如果没有获取到,就使用Factory创建,然后存入ViewModelStore。
总结
- Activity持有ViewModel,一个Activity可以有多个类型的ViewModel;
- 同一个类型的ViewModel在Activity中有且只有一个实例;
- 通过HashMap和工厂模式保证了单一类型ViewModel的单例;
- ViewModel生命周期贯穿整个Activity,且不会重复创建。