Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
简介
ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
ViewModel
是一个抽象类,内部值得关注就是onCleared()
方法,我们可以在此方法中释放资源等操作。
ViewModelStore
是个很重要的成员,它主要就是用来保存ViewModel
对象,保证Activity在屏幕旋转之后ViewModel
中的数据不丢失,内部有一个Map
来保存所有的ViewModel
。
ViewModelProvider.Factory
乍一看就知道是一个工厂类,其实它是ViewModelProvider
内部接口,只有一个create(clazz)
方法,该方法主要就是用来创建ViewModel
对象,我们常用的有NewInstannceFactory
和AndroidViewModelFactory
。
ViewModelProvider
则是负责如果中转作用,将factory生成的viewmodel存到store中,如果store中已经有值,直接返回已存在的对象。
ViewModelStore
作用上面已经提过,直接看源码吧~
public class ViewModelStore {
// 用于保存ViewModel对象的集合,key是ViewModel类的canonicalName,所以key是唯一的
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());
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
ViewModelStore
源码还是很简单的,就类似于一个数据存储类,一个ViewModel
对象只会存储一份。
ViewModelProvider.Factory
Factory
接口只有一个方法,我们下面结合NewInstanceFactory
源码一起看下实现原理。
public interface Factory {
/**
* Creates a new instance of the given `Class`.
*
* @param modelClass a `Class` whose instance is requested
* @return a newly created ViewModel
*/
public fun <T : ViewModel> create(modelClass: Class<T>): T
}
public open class NewInstanceFactory : Factory {
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return try {
modelClass.newInstance()
} catch (e: InstantiationException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
} catch (e: IllegalAccessException) {
throw RuntimeException("Cannot create an instance of $modelClass", e)
}
}
}
NewInstanceFactory
是官方默认的一种实现,create()
方法很简单,就是根据Class
实例化出一个对象。
到此我们知道Factory
可以实例化一个ViewModel
对象,然后存到ViewModelStore
中,最后我们看看ViewModelProvider
是如何将这两个结合起来的。
ViewModelProvider
在这我们先看下如果通过ViewModelProvider
来获取一个ViewModel
对象,常用的写法:
val viewModel = ViewModelProvider(
viewModelStore,
ViewModelProvider.NewInstanceFactory.instance
).get(Vm::class.java)
- 创建
ViewModelProvider
对象需要两个参数,这两个我们在上面都解析过,这里viewModelStore
是通过Activity
中的getViewModelStore()
获取而来,一个Activity
维护了一个ViewModelStore
对象,并且在屏幕旋转重建之后此对象不变,可以了解下NonConfigurationInstances
的原理。 - 通过
ViewModelProvider.get(Clazz)
得到ViewModel
实例,下面重点看下这个方法。
@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
val canonicalName = modelClass.canonicalName
?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
// 1、拼接key值,调用两个参数的get()方法
return get("$DEFAULT_KEY:$canonicalName", modelClass)
}
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
// 2、先看看ViewModelStore中是否存在此ViewModel
var viewModel = store[key]
if (modelClass.isInstance(viewModel)) {
(factory as? OnRequeryFactory)?.onRequery(viewModel)
return viewModel as T
} else {
@Suppress("ControlFlowWithEmptyBody")
if (viewModel != null) {
// TODO: log a warning.
}
}
// 3、不存在调用Factory.create()去实例化
viewModel = if (factory is KeyedFactory) {
factory.create(key, modelClass)
} else {
factory.create(modelClass)
}
// 4、存入ViewModelStore中
store.put(key, viewModel)
return viewModel
}
ViewModelProvider.get()
方法逻辑十分清晰,上述注释我分了4步解释,这里就不再啰嗦了~