关于ViewModel的这几个问题,你都知道吗?
作为一名Android开发者,如果你熟悉MVVM架构
,熟悉Jetpack
组件,那么相信你肯定使用过ViewModel
。
正如它的名字一样,它是Google推出的一个类,方便我们实现MVVM架构
中的ViewModel层
。我们在其中处理View层
所需的数据,然后在特定条件下通知View层
进行UI更新
。
正如官方所介绍:
ViewModel
类以注重生命周期的方式存储和管理界面相关的数据。ViewModel
类让数据可在发生屏幕旋转等配置更改后继续留存。
我们抓一下这句话的重点:
注重生命周期的方式:会在合适的时间进行自我回收,防止出现内存泄漏。
存储和管理界面相关的数据:符合
MVVM架构
中ViewModel层
的理念。在发生屏幕旋转等配置更改后继续留存数据:为什么要这么设计?怎么做到的。
接下来,就让我们带着问题,深入学习一下ViewModel类。
使用方法
在阅读源码前,让我们先来简单回顾一下ViewModel的使用方法。
class MainViewModel(private val repository: MainRepo) : ViewModel() {
private val _textMld = MutableLiveData<String>()
val textLd: LiveData<String> = _textMld
fun getTextInfo() {
viewModelScope.launch {
withContext(Dispatchers.IO) {
//做异步网络请求工作,获取到textData
repository.getTextInfo()
}.apply {
_textMld.postValue(textData)
}
}
}
}
class MainActivity : AppCompatActivity() {
fun setVmFactory(): ViewModelProvider.Factory {
return object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return MainViewModel(MainRepo()) as T
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val vm = ViewModelProvider(this, setVmFactory())[MainViewModel::class.java]
vm.textLd.observe(this, Observer {
binding.textTv.text = it
})
}
}
方法步骤可以简单分为两步,分别为:
继承ViewModel
类实现自定义ViewModel
,如:MainViewModel。通过
ViewModelProvider
来实例化ViewModel
。
源码
现在,根据上方所介绍的使用方法,我们进一步来看一下ViewModel的源码。
public abstract class ViewModel {
....
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
@MainThread
final void clear() {
....
onCleared();
}
....
}
ViewModel 是一个抽象类,提供 onCleared()
方法供我们在ViewModel销毁前做一下清除工作。
接下来,我们来看看是如何通过ViewModelProvider
来实例化ViewModel对象的。
其实就是两步:
实例化一个
ViewModelProvider
对象。调用
ViewModelProvider.get()
方法来得到一个ViewModel
对象。
先来看看它的构造函数:
public open class ViewModelProvider(
private val store: ViewModelStore,
private val factory: Factory
) {
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner))
public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
owner.viewModelStore,
factory
)
......
}
通过 ViewModelProvider
的构造函数可以看出,一共有两个参数:ViewModelStore
与 Factory
。
分别来看看这两个参数代表着什么意思。
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
//所以这里key需要注意,不要使用相同的key,否则后创建的VM会替换到老的VM
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());
}
public final void clear() {
for (ViewModel vm : mMap.values()) {
//调用ViewModel的clear方法,表示不再使用
vm.clear();
}
//清除集合中的所有ViewModel
mMap.clear();
}
}
ViewModelStore
:正如其名,就是用来存储ViewModel
对象的,通过内部维护一个HashMap
来实现对ViewMoel对象的存储与管理工作。
再来看看上面所介绍的 Factory
。
而Factory则是工厂接口的,用来实例化ViewModel,具体实现可以参考使用方法中所介绍的 setVmFactory()
方法,用来实例化 MainViewModel。
public interface Factory {
public fun <T : ViewModel> create(modelClass: Class<T>): T
}
接下来,我们来看看 ViewModelProvider
中的 get()
方法。
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
val canonicalName = modelClass.canonicalName
return get("$DEFAULT_KEY:$canonicalName", modelClass)
}
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
//1.根据key从ViewModelStore中取出ViewModel
var viewModel = store[key]
//2.通过工厂方法来实例化viewModel
if (modelClass.isInstance(viewModel)) {
(factory as? OnRequeryFactory)?.onRequery(viewModel)
return viewModel as T
}
viewModel = if (factory is KeyedFactory) {
factory.create(key, modelClass)
} else {
factory.create(modelClass)
}
//3.将实例化的ViewModel放入ViewModelStore
store.put(key, viewModel)
return viewModel
}
概括一下 get()
方法:
根据传入的形参
Class.canonicalName
做为key,从ViewModelStore
中取出ViewModel。再通过工厂方法来实例化ViewModel。
最后将实例化后的ViewModel放入
ViewModelStore
中,并返回。
OK,根据使用方法来分析源码的话,我们好像已经分析完了