ViewModel作为Android JetPack里面的重要的一员,确实担任了一个十分重要的角色。也是实现MVVM架构的基础。所以会用并不能代表什么,而稍微把原理理清楚,你可以获得更多的知识(面试八股文)
1.不会因为屏幕旋转等Actiity配置而导致销毁.
2.跟随生命周期
这里就不说明APi的使用了,网上文章太多了…
这里只分析AndroidX
我们来看一下他为什么可以跟随生命周期把.
我们入口使我们的实例化过程
viewModel = ViewModelProvider(this).get(DemoViewModel::class.java)
在ViewModelProvider.java中
可以看到它就是用的构造函数,而构造函数使用了getViewModel()函数
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);
}
从getViewModel进入,会发现是一个接口,那它的实现类是在哪呢?
跟踪后发现是在CompontActivity.java中
可以发现,mViewModelStore就在这进来的,若为空则从一个叫做NonConfigurationInstances
中获取,若里面没有东西则新建一个ViewModelStore.
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;
}
这里产生两个问题:
ViewStore是干嘛的?
NonConfigurationInstances又是干嘛的?
进入ViewStore类我们可以看到,它是存放ViewModel的一个存储类
,里面用hashmap保存ViewModel. 这里留下这个clear()函数的伏笔
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final ViewModel get(String key) {
return mMap.get(key);
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
NonConfigurationInstances的获取是由getLastNonConfigurationInstance()函数得到进入该函数
你会不知道写了什么东西.但是翻看官方文档得知,这个实例由onRetainNonConfigurationInstance()返回
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
还是在ComponentActivity.java中找到该函数。
可以清楚的看到,nci偷偷的保存了viewModelStore.并且返回了该实例,这里返回的NonConfigurationInstances()类,就是getLast…返回的实例
public final Object onRetainNonConfigurationInstance() {
// Maintain backward compatibility.
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;
}
所以我们也找到了保存的地方,在返回的地方我们也找到了~所以这就是在Activity配置转换的时候,viewModel不会被销毁的原因了.
来,官方文档经典生命周期.
可以看到,Viewmodel实在OnDestory后才onCleared的.那么我们的onCleared在那里调用以及如何保证的呢?.还记得我们上面留下的伏笔吗?
进入到该oncleared()函数,看他在哪里调用的.
仍然是ComponentActivity.java中
可以看到它直接用的是Lifecycle中的观察方式了.
So,Lifecycle也是JatPack的一员,它直接应用到这里了。
如果有不明白的可以先去了解一下Lifecycle.
public ComponentActivity() {
Lifecycle lifecycle = getLifecycle();
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
// Clear out the available context
mContextAwareHelper.clearAvailableContext();
// And clear the ViewModelStore
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
2022.5.20更新…
我们知道ViewModel其中的一个功能就是它的作用是根据自己的宿主决定的。如果是同一个ViewModel类,但是一个绑定Fragment,一个绑定的是Activity.那么两个的数据互不影响,也无法通信.
还记得我们上面说的.ViewStore嘛?ViewModel的创建就是初始化它和一个Factory.
我们看NewInstanceFactory
使用了其反射构造方法去创建该类对象
我们再看它最终要执行的get()方法
最终拼接key。是否能从缓存中取出,不行则通过工厂创建并且存入缓存.所以,如果有作用域,那么Activity/Fragment必定会实现获得该实例的接口
我们回头看一下ComponentActivity
可以看到它确实实现了该接口…
Fragment的话去查看FragmentManager.getViewModelStore()
所以他们内部都有去做实现去获取ViewModelStore的接口。又因为key,获取到了同一个ViewModel,以此来保证可控的作用域
Fragment → FragmentManager → FragmentManagerViewModel → mViewModelStores集合
所以:ViewModel的作用域可控 = 工厂模式 + 缓存集合(特定key规则)。
又水了一篇,真开心~