这里记下个人对Viewmodel的总结
Viewmodel创建到使用
关于viewmodel,我自己也知识在项目里面用到了,并没有去深究它的原理和来路,一次开发的时候突然想到,两个activity要用到同一个viewModel,但是view model又不是new出来的对象,那是如何储存的呢,于是就想了解下viewmodel的从创建到使用。
- ViewModel创建
Viewmodel不能通过new来创建,只能先根据Activity或者Fragment获得ViewModelProvider,之后通过ViewModelProvider来创建,其中的of方法获取ViewModelProvider的静态内部类AndroidViewModelFactory(单例),然后让其通过反射创建指定的viewmodel,之后通过ViewModelStore的HashMap存储ViewModel并将其返回
这里可以总结三点
第一: AndroidViewModelFactory在正常情况下是全局单例只有一个,只是一个反射创建对象的工具类。
第二:ViewModelProvider是每次获取创建ViewModel的时候都会创建一个新的。
第三:ViewModelStore是每一个Activity或者Fragment都有一个。 - ViewModel的储存
每次ViewModel被创建的时候都会创建一个HolderFragment,其中持有ViewModelStore并储存着Viewmodel,当activity屏幕翻转调用onDestory时候会将此时的hashmap保存下来。
.Activity或者Fragment的HolderFragment会保存在全局单例的HolderFragmentManager的HashMap中,在Activity或者Fragment销毁的时候会移除HashMap中对应的value。
最后附上viewmodel经典的一张生命周期图
参考文章
Android架构组件ViewModel来龙去脉
关于codelabs对Viewmodel的解说疑惑
先贴上疑惑的地方
class SharedViewModel : ViewModel() {
val selected = MutableLiveData<Item>()
fun select(item: Item) {
selected.value = item
}
}
class MasterFragment : Fragment() {
private lateinit var itemSelector: Selector
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
itemSelector.setOnClickListener { item ->
// Update the UI
}
}
}
class DetailFragment : Fragment() {
// Use the 'by activityViewModels()' Kotlin property delegate
// from the fragment-ktx artifact
private val model: SharedViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
// Update the UI
})
}
}
请注意,这两个 Fragment 都会检索包含它们的 Activity。这样,当这两个 Fragment 各自获取 ViewModelProvider
时,它们会收到相同的 SharedViewModel
实例(其范围限定为该 Activity)。
上面是codelab对viewmodel 的一段解释,说的是不同fragment可以得到同一个viewmodel实例,通过前面的分析我们知道ViewModelProvider是每一个fragment和activity都各自持有的,这里用了fragment_ktx库的方法来给两个fragment注入相同的viewmodel实例,就可以实现数据共享。如果是java,就是这样
model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);