How to code the MVVM in Android
MVVM
- 一种通过观察者模式实现数据回调的单一数据源结构
- 核心结构(这个图是结合我的理解用ProcessOn画的,每个人理解可能会有不同的偏差,如果有不同看法,结合你的业务去理解会更好)
ViewModel的创建方式很简单,按照官方的推荐,注入相应的生命即可以获取到相应的ViewModel,当然它这里还涉及到工厂模式,这部分详细参见ViewModelProvider.Factory:
- 自己生命周期的
kotlin
private val viewModel: MyViewModel by lazy {
ViewModelProvider(
this,
MyViewModelFactory()
)[MyViewModel::class.java]
}
- 父容器生命周期的
kotlin
private val parentViewModel: RouteViewModel? by lazy {
parentFragment?.let {
ViewModelProvider(
it,
MyViewModelFactory()
)[RouteViewModel::class.java]
}
}
private val activityViewModel: ActivityViewModel? by lazy {
activity?.let {
ViewModelProvider(
it,
MyViewModelFactory()
)[ActivityViewModel::class.java]
}
}
ViewModel的实际编写和LiveData的使用
kotlin
class MyViewModel(
private val repository: Repository,
): ViewModel() {
private val _data: MutableLiveData<String> = MutableLiveData()
val data: LiveData<String> = _data
private val _errorMessage: MutableLiveData<Throwable> = MutableLiveData()
val errorMessage: LiveData<Throwable> = _errorMessage
private val _isRefresh: MutableLiveData<Boolean> = MutableLiveData()
val isRefresh: LiveData<Boolean> = _isRefresh
fun fetchData() {
_isRefresh.value = true
viewModelScope.launch(Dispatchers.Main + CoroutineExceptionHandler { _, throwable -> {
_errorMessage.value = throwable
_isRefresh.value = false
}}) {
// Image repository.fetchData() run in background thread to fetch data.
// Warning: when you want to post something to livedata, you need to stay at UI Thread.
_data.value = repository.fetchData()
_isRefresh.value = false
}
}
}
class MyFragment: Fragment() {
private val viewModel: MyViewModel by lazy {
ViewModelProvider(this)[MyViewModel::class.java]
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.isRefresh.observe(this) {
showHideSpinner(it)
}
viewModel.errorMessage.observe(this) {
Toast.makeText(context, it.message, Toast.LENGTH_SHORT).show()
}
viewModel.data.observe(this) {
updateUI(it)
}
viewModel.fetchData()
}
private fun updateUI(data: String) {
// updateUI
println(data)
}
}
- MVVM与MVP的不同,就是MVVM并不一定要采用双向绑定,受限于DataBinding双向绑定的能力实在是太弱了,在使用MVVM的时候,我个人更加喜欢使用单一数据源,这也是Google最推荐的方式。结合着LiveData这一个拥有生命周期注入的监听工具,ViewModel中的数据可以很方便返回给到View。
- 值得提及的一点是,我个人常用的单Activity多Fragment模式,使用parentFragment的生命周期去实现路由跳转是一个很好解决路由问题的方式。
- 当然不可避免的一点,当我们使用LiveData的时候,按照以往既定的想法,每一个LiveData会对应一个状态。像上面的示例,它就存在了刷新中、数据请求成功、数据请求失败着3个状态。 这就会导致在ViewModel中,LiveData变得异常多,我们俗称为LiveData爆炸。