ViewModel是Jetpack提供给我们使用的一个组件,他的作用是可以作为View和Model的中介,使得数据和页面分离,同时能避免内存泄漏的问题。
使用
我们讲解的ViewModel版本是2.2.0
的,下面是使用ViewModel的步骤:
- 继承
ViewModel
抽象类 - 在
Activity/Fragment中
通过ViewModelProvider创建ViewModel
继承类实例 - 把页面(Activity/Fragment)与数据的交互操作放到继承类中,继承类一般还有一个
repo
去负责请求网络数据或者是读取本地数据。这样就把ViewModel
当做一个中介。
当然,我们使用ViewModel还可以配合DataBinding,可以把ObserverField
或者是LiveData
相关的变量作为ViewModel的成员变量,同时把该ViewModel注入到对应的xml中,而且一般也是这样使用的。
1 | class TestVM : ViewModel() { |
大概的使用就是如上面的一样,ViewModel更多的时候是一个载体,存有LiveData和ObserverField等数据。
源码解读
我们先看他的类图
然后分析一下他的关键类作用:
- ViewModelStore,他是用于存储ViewModel对象的地方,他的
clear
方法可以清楚ViewModel,同时也会独一调用ViewModel的clear
方法 - ViewModelStoreOwner,是一个接口,用于获取ViewModelStore对象,比如我们的ComponentActivity(androix.activity的1.2.2版本)就实现了该接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25@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.");
}
ensureViewModelStore();
return mViewModelStore;
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
} - ViewModelProvider,他是用于创建ViewModel实例的地方,通过
Factory
接口定义的方法去创建,创建完成之后,会存入ViewModelStore中。我们重点分析一下他的构造函数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
//假如没有自定义创建ViewModel的Factory,则判断是否owner是否实现了HasDefaultViewModelProviderFactory
//HasDefaultViewModelProviderFactory也是一个接口,定义了一个返回Factory的方法,是getDefaultViewModelProviderFactory
//假如不是,那么就使用NewInstanceFactory作为创建ViewModel的方式
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
//存入了owner以及factory
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
this(owner.getViewModelStore(), factory);
}
//直接传入store和factory
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
} - Factory,它定义了创建ViewModel的方式,在ViewModelProvider中提供了两种,一种是ViewModel没有Application的,使用
NewInstanceFactory
,还有一个是AndroidViewModelFactory
,他有Application。我们再看ViewModelProvider创建ViewModel的时候,他是先读取缓存,缓存不存在,则调用Factory创建,而ViewModelProvider中提供的Factory创建是通过反射的。通过上面代码,我们知道,假如我们的ViewModel需要通过NewInstanceFactory创建,那么他必然需要一个无参数构造函数,假如是通过AndroidViewModelFactory创建,则必须要需要一个只有一个参数为Application的构造函数。当然我们也可以不用这两种Factory,而是自己实现Factory的create去生成也可以。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44//ViewModelProvider创建ViewModel
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//已经存在了该ViewModel
if (mFactory instanceof OnRequeryFactory) {
//调用查询,通知外部
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//调用Factory创建,
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
//NewInstanceFactory的创建
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.newInstance();
}
...
}
//AndroidViewModelFactory的创建
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
//noinspection TryWithIdenticalCatches
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
}
...
return super.create(modelClass);
}
5.ViewModel,他是一个抽象类,并无抽象方法,他有一个onCleared
的方法我们可以重写,他会在Activity被销毁的时候回调,我们可以清除数据。他的mBagOfTags
是用于存储一些需要寄宿在ViewModel上的对象,这些对象在ViewModel被回收的时候也会被清除,假如这些对象实现了Closeable接口,则还会被调用close
方法。比如现在的viewmodel-ktx,他提供了在ViewModel中获取协程对象的快速方式,该协程对象就是存入到mBagOfTags
中,同时对该协程对象进程了一层包装实现了Closeable
接口,就可以包装在ViewModel被回收的时候,协程对象也可以被cancel
。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17val ViewModel.viewModelScope: CoroutineScope
get() {
//获取协程对象
val scope: CoroutineScope? = this.getTag(JOB_KEY)
if (scope != null) {
return scope
}
return setTagIfAbsent(JOB_KEY,
CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
}
internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
//取消协程执行
coroutineContext.cancel()
}
}
总结就是我们的Activity/Fragment通过实现ViewModelStoreOwner接口,获取到ViewModelStore对象,而ViewModelStore是缓存ViewModel的。然后在编写代码的时候,通过ViewModelProvider创建ViewModel,创建的方式是通过ViewModelProvider的内部接口Factory管理的。
而如何做到让ViewModel感知生命周期的呢?我们可以看到在ComponentActivity中,有这样的一段代码
1 | getLifecycle().addObserver(new LifecycleEventObserver() { |
从中可以得知ViewModel是通过Lifecycle去得知所处组件的生命周期的。
初识SavedState
我们在androidx.activity的1.2.2版本中看到了ComponentActivity是实现了HasDefaultViewModelProviderFactory的,也就是使用了ViewModelProvider(@NonNull ViewModelStoreOwner owner)
构造函数,传入或者他的子类,则会使用它实现了Factory对象去创建ViewModel,我们看下她提供的Factory有何特点。
1 | public ViewModelProvider.Factory getDefaultViewModelProviderFactory() { |
SavedStateViewModelFactory
是位于组件lifecycle-viewmode-savedstate
中的,同时还牵扯到另外一个savedstate
组件。我们再后面的文章再去分析它,具体请看savedstate