概念
试图数据管理类,ViewModel负责准备和管理跟UI组件(Activity,Fragment)相关的数据类,同时还可以用来负责UI组件间的通信。
存在的意义
a.页面销毁重新创建后(如旋转屏幕,异常销毁等),原来的UI相关数据会丢失,理论上可以通过onSaveInstanceState()存储数据,组件重建之后通过onCreate(),从中读取Bundle恢复数据。但如果是大量数据,Intent源码限制1M大小,实际可用大概512k左右,超过时不能储存。
b.基于架构层次考虑,UI controllers其实只需要负责展示UI数据、响应用户交互和系统交互,但是现存MVP架构中presenter层过于庞大,Aciivity与Fragment也难以做到试图分类。
生命周期:
左侧表示Activity的生命周期状态,右侧绿色部分表示ViewModel的生命周期范围。ViewModel只有onCleared()在结束时调用,Activity生命周期照旧。注意当旋转屏幕时,在不设置onConfig属性的情况下,Activity会被reCreate,但是VidewModel还是之前的对象,没有重新创建。
ViewModel原理
1.创建
a.viewModel初始化通过ViewModelProvider获取ViewModel实例,先看ViewModel源码其构造方法:
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);
}
ViewModelProvider的构造方法中可以看到最终是需要两个参数ViewModelStoreOwner以及Factory。这两个参数中ViewModelStoreOwner是用来存储ViewModel对象的,Factory是用来创建ViewModel对象。
b.ViewModelProvider的get()方法获取ViewModel实例
public
ViewModel viewModel = mViewModelStore.get(key); // 1.是否有缓存ViewModel实例缓存
...
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
通过Factory创建ViewModel后,讲viewModel放置在mViewModelStore缓存中
c.ViewModelStoreOwner,ViewModelStore
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
public class ViewModelStore {
private final HashMap
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.get(key);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
mMap.put(key, viewModel);
}
final ViewModel get(String key) {
return mMap.get(key);
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.onCleared();
}
mMap.clear();
}
}
源码中我们传入的组件ViewModelStoreOwner,通过getViewModelStore方法获取到的ViewModelStore对象,从源码中我们能够看到,在ViewModelStore内部是保存了一个HashMap,key就是ViewModel的全类名,所以在调用get方法时,从store拿到的ViewModel就是我们要创建的这个实例
2.销毁
a.ViewModel中有clear()方法和onCleared()都执行了clear方法,进行vm.clear与清除缓存HashMap缓存的 操作
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
b.继续跟踪代码能查看到Activity与Framgent执行getViewModelStore().clear()方法的时机
public ComponentActivity() {
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
// 销毁ViewModel
getViewModelStore().clear();
}
}
}
});
}
void clearNonConfigState(@NonNull Fragment f) {
...
// Clear and remove the Fragment's ViewModelStore
ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
if (viewModelStore != null) {
// ViewModel销毁
viewModelStore.clear();
mViewModelStores.remove(f.mWho);
}
}
这里有个点需要注意,ViewModel的销毁在onDestory()中,是晚于onDestoryView()的,所以要注意在使用ViewModel做操作时会不会触发组件更新。不然的话可能造成空指针异常。
3.ViewModel的缓存策略
在Activity重建时会执行destory生命周期事件,那么为什么ViewModel没有销毁呢?
public ViewModelStore getViewModelStore() {
...
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()方法时优先从getLastNonConfigurationInstance()方法获取,如果getLastNonConfigurationInstance()方法没有缓存,才会去新建对象。
NonConfigurationInstances 持有并储存viewModelStore对象,viewModelStore对象的HashMap中存储ViewModel对象。
4.Fragment之间共享ViewModel
inline fun
noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })
在activityViewModels()的实现中可以看到是requireActivity()获取的viewModelStore。以此来实现共享ViewModel。
相关文章
发表评论