本来这篇文章很早就应该写的,一直没(比)有(较)时(懒)间
今天决定把它写完咯
首先表明态度, I think:
网上流传的ViewModel+LiveData+ XXX 的号称MVVM的代码设计基本都是假的(fake news :P)
MVVM
首先说一下 MVVM 这种架构模式(或者说设计模式),我对它的认识源于维基百科

我们来看看关于 MVVM 各组件的标准定义
model: 没啥好说的,跟MVPMVC之流大差不差,定义了业务(数据)逻辑和数据的模型view: 还是没啥好说的,就是视图层,用户界面view-model: 关键在这里,我们所谓的view-model其实是从presenter胶水演化出来的,暴露视图的公开属性和指令,本质上就是view视图对应的一个model- 首先,它是一个 view model,对
model层暴露来自view层的一些公开属性,以及来自view层的一些指令(presenter?) - And,binder:
view-model区别于presenter与controller,它有一个称之binder的东西,作用是处理 view-model 中暴露的视图属性(状态)与视图 UI 的自动同步
- 首先,它是一个 view model,对
所以 MVVM 模式下的流转路径应该是这样的:
view: user input event ->view-model: view property or commandview-model: handle input, biz model ->model: biz data/logic processingmodel: state chagne events(data) ->view-model: handle biz stateview-model: ui state update ->binder: handle ui state synching
MVP
ok,我们再来看一下 MVP 是怎么流转的

view: User input event ->presenter: function (command)presenter: biz model ->model: biz data/logic processingmodel: state change events(data) ->presenter: convert biz statepresenter: biz state/data ->view: refresh ui
仔细对比一下往上流传的基于 Jetpack ViewModel + LiveData 的伪 MVVM(MVP)的流转情况:
Activity/Fragemnt->ViewModel, 这是view->presenterViewModel调用model处理网络请求、数据逻辑、文件 IO 等业务逻辑,这是presenter->model- 这里我们看一下在
ViewModel中完成了业务逻辑通知 UI 刷新,通过LiveData的setValue/postValue更新状态,
view 层通过 viewModel.xxxLiveData.observe(lifecycleOwner) { data -> … }
在最后一个环节,我们对比一下经典的 MVP 模式的写法:presenter 通过持有的 view 接口通知视图变更,view 层在对应的接口实现中完成对 UI 组件的更新
看 ~ 发现了什么
即使是通过 LiveData 观察者模式在 view 层实现对数据的观察,省去了经典 MVP 写法的 view 接口定义和耦合,但是在事件(数据)流转的路径上,依然是走的 MVP 的模式
对比 MVVM 定义的工作流程,不难发现,其中最大的差异在于 binder 这个角色的存在
binder 作为实现数据和 UI 同步的重要组件,同时按照 MVVM 模式的定义,属于 view-model 的内部成员
因此可以得出结论:MVVM 的关键在于,用户事件的流转是单向,从 view 层开始,到 view-model 结束;而这其中的关键在于 binder
Jetpack data-binding
Databinding 就是 Google 爸爸为我们提供的一个官方 binder 实现方案
即:
MVVM中的binder可以直接使用官方data-binding组件来实现- 不使用
data-binding组件,自定义处理数据与 UI 的同步的binder并在view-model中维护,也是规范的 MVVM 写法
DataBinding 分为两个部分
ViewDataBinding:每个被 <layout> 标签包裹的布局都会对应生成一个 ViewDataBinding 的子类作为视图与数据绑定的管理者Observable/BaseObservable: 实际的 binder 开发接口,需要绑定与 view 层建立绑定关系的数据通过实现此接口并注册成员,即可自动完成监听与同步(实际代码在生成的 XxxLayoutBindingImpl 类中)
关于 DataBinding 的使用及原理,此处不予赘述
MVVM 在实际项目中的落地
sample Activity
1 | class SampleBindingActivity : AppCompatActivity(), ActivityBindingHolder<SampleActivityBinding> by ActivityBinding(R.layout.sample_activity) { |
sample layout
1 | <layout xmlns:android="http://schemas.android.com/apk/res/android"> |
sample view-model
1 | class SampleViewModel : ViewModel() { |
sample binder
1 | class SampleBinder : BaseObservable() { |
注:
ActivityBindingHolder 👉🏻 android-zanpakuto: ActivityBinding.kt
func: viewModel 👉🏻 android-zanpakuto: ViewModel.kt
func: ObservableProperty 👉🏻 android-zanpakuto: ObservableProperty.kt
func: observableField 👉🏻 android-zanpakuto: ObservableAttribute.kt