一、简单介绍下ViewModel有什么作用和优点
二、类图总结ViewModel原理
有错漏之处 请多多指教。
ViewModel作用
通常与LiveData一起使用,
(1)将activity, fragment里关于数据操作的逻辑抽离出来,封装到ViewModel中,所以ViewMoel 持有一个成员变量LiveData
(2)数据的操作包括什么呢? a. 从DB和缓存读取数据,显示到UI; b. 通过网络到后台拉取数据,持久化到本地,更新DB和缓存,通知UI刷新。
(3)因此ViewModel 应该持有一个 成员变量Repository(相当于一个管理类, 命名可以命名为其他如XXXManager),做(2)的事情。 而组件activity, fragment应该持有一个成员变量ViewModel , 如图所示
图片来源LiveData + ViewModel + Room (Google 官文)+Demo - 简书
demo地址:MVVM: ViewModel+LiveData+DataBinding+Retrofit+Room+Paging+RxJava 总结与实践(Java实现)_xiaobaaidaba123的专栏-CSDN博客
ViewModel优点
1. 当横竖屏发生切换时,activity会重建,但是ViewModel不需要重建。
2. ViewModel可以避免内存泄漏问题,Activity destroy时会调用ViewModel的onCleared()方法。
3. 可以解决同一个Activity的不同Fragment的数据共享问题。
ViewModel 原理学习总结
【ViewModelProvider】一两句话总结
1) ViewModelProvider持有两个成员变量 ViewModerStore ——存储ViewModel 和 Factory —— 创建ViewModel。
因此了解ViewModelProvider 的职责——可以把它看成一个wrapper——打包了创建ViewModel和存储ViewModel的功能。
public class ViewModelProvider {
private static final String DEFAULT_KEY =
"android.arch.lifecycle.ViewModelProvider.DefaultKey";
/**
**************************************************
* ViewModelProvider持有的两个成员变量
**************************************************
*/
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
/**
**************************************************
* 实现Factory接口来创建ViewModel
**************************************************
*/
public interface Factory {
T create(Class modelClass);
}
/**
**************************************************
* ViewModelProvider构建方法
* 参数 ViewModelStoreOwner 和 Factory
* ViewModelStoreOwner 是一个接口,可以返回ViewModelStore
**************************************************
*/
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
/**
**************************************************
* ViewModelProvider构建方法
* 参数 ViewModelStore 和 Factory
**************************************************
*/
public ViewModelProvider(ViewModelStore store, Factory factory) {
mFactory = factory;
this.mViewModelStore = store;
}
/**
**************************************************
* 先获取modelclass名字,再调用get (key, modelclass) 获取ViewModel
**************************************************
*/
public T get(Class 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);
}
/**
**************************************************
* 通过key值从ViewModelStore 中获取ViewModel, 如果没有,则通过factory构建一个,再存储到
* ViewModelStore
**************************************************
*/
@NonNull
@MainThread
public T get(@NonNull String key, @NonNull Class modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = mFactory.create(modelClass);
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
/**
**************************************************
* 该工厂类 通过java反射构建ViewModel 调用无参构造方法
**************************************************
*/
public static class NewInstanceFactory implements Factory {
@Override
public T create(Class 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);
}
}
}
}
【ViewModelStore】一两句话总结
1)ViewModelStore作用很简单——内部持有一个HashMap,存储ViewModel
public class ViewModelStore {
/**
**************************************************
* hash map存储viewModel
**************************************************
*/
private final HashMap mMap = new HashMap<>();
/**
**************************************************
* put方法
**************************************************
*/
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.get(key);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
mMap.put(key, viewModel);
}
/**
**************************************************
* get方法
**************************************************
*/
final ViewModel get(String key) {
return mMap.get(key);
}
/**
**************************************************
* 清除hashMap
**************************************************
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
横竖屏切换,为什么ViewModel不会重建
1)Activity销毁前,先把ViewModelStore保存起来
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
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;
}
2)Activity 重建后调用getViewModelStore()