MVVM架构优化
前言
关于MVVM优秀的架构,目前市面上有挺多:例如:MVVMHabit , Jetpack-MVVM-Best-Practice ,其中MVVMHabit主要是针对ViewModel的能力的扩充,Jetpack-MVVM-Best-Practice 主要是以Clean Architecture设计思想为基础的层次划分;但是都没有涉及到特别复杂页面的架构设计,例如在页面特别复杂的情况下,ViewModel的代码量将是巨量,如何解决这类问题?
1.MVVMHabit
![](https://img.haomeiwen.com/i7161394/2718b611f56950d4.png)
ViewModelxxx
所有的ViewModel实现类,其中包含了ViewModel的本职工作(google赋予它的能力),也就是视图相关的状态托管及管理
BaseViewModel
在ViewModel的本职工作之外扩充了它的能力showDialog,startActivity等(主要是通过LiveData分发数据,让监听LiveData的BaseActivity处理具体事务);UIChangeLiveData uc 这个是统一管理上述LiveData
IBaseViewModel
自定义的LifecycleObserver观察者,在对应方法上用注解声明想要观察的宿主的生命周期事件,在宿主中addObserver后即可接受宿主分发的相应事件。也即跟宿主生命周期有了个绑定。
Lifecycle
Lifecycle 是具备宿主生命周期感知能力的组件。它能持有组件(如 Activity 或 Fragment)生命周期状态的信息,并且允许其他观察者监听宿主的状态。它也是 Jetpack 组件库的的核心基础。
再也不用手动分发宿主生命周期,在也不用手动反注册了。
![](https://img.haomeiwen.com/i7161394/3feeabc23cc8e0db.jpg)
具体Lifecycle的实现原理,文章后面有补充,因为不在主流程中,就不在这块占地方了。
BaseActvity
作为宿主持有viewModel,让viewModel感应宿主生命周期;监听viewModel中liveData的回调,处理startActivity等操作
Actvityxxx
用于初始化viewModel及initVariableId()
MVVMHabit总结
![](https://img.haomeiwen.com/i7161394/2f7b7fefe0a8b258.png)
ViewModel跟视图(Activity/Fragment)一一对应的关系,通过对ViewModel的能力扩充,使其有自己的生命周期管理及各种能力;承担了原来视图中的数据请求,业务逻辑及视图状态托管(liveData)的工作。
2.改造ViewModel
复杂的页面(十多个接口的数据获取及拆开的十几个xml中的交互),对单ViewModel绝对不太友好(成千上万行代码),所以ViewModel的改造势在必行,造成ViewModel臃肿的主要原因是"能力越强责任越大",也就是给ViewModel扩充的能力太多导致,有两种减压方案:
- 职能的拆分
- 拆多ViewModel
2.1职能的拆分
回到ViewModel的本职工作:
ViewModel 的本职工作是 状态托管 和 状态管理 ,其中状态数据变化时驱动视图的改变。所谓数据驱动,本质上不过是编译时注解自动生成的、以适配器模式来运筹帷幄、以观察者模式 来监听和通知视图改变状态。
ok,说的直白点,ViewModel中仅仅用来放置LiveData就好了,这就是系统给他的工作,当然了,如果是比较简单的页面,让ViewModel承担别的责任也无可厚非,因为官网也没制止这种行为。
现在问题来了,既然ViewModel不做这些工作,那要谁来做?嗯,是时候祭出我们的软件行业的镇宅图了。
Clean architecture
![](https://img.haomeiwen.com/i7161394/cc63ac8f642d9288.jpeg)
这种看起来像“洋葱”的环形图就是Clean Architecture,不同颜色的“环”代表了不同的系统结构,它们组成了整个系统,箭头则代表了依赖关系
分层
- 外层:实现层
- 中间层:接口适配层
- 内层:业务逻辑层
实现层
一句话:实现层就是Android框架层,包括Android的东西,与平台特性相关,例如:Activity的跳转,开启Service等。
接口适配层
接口适配层的目的是连接业务逻辑与框架特定代码,担任外层与内层之间的桥梁。例如Presenters,Controllers
业务逻辑层
这一层解决所有的业务逻辑,不包含Android平台的任何代码,可以单独提出来测试,在我们做平台化的时候,这一层的一些UseCase(一个Request可以理解为一个UseCase)也可以被共用,拆分的力度会细些
实现方案
有了上述理论的支持,对ViewModel职能拆分后的设计如下:
![](https://img.haomeiwen.com/i7161394/897318284a0e724c.png)
补充
实际上的Clean architecture设计思想还涉及到内外环的依赖规则及抽象原则,外圈跟内圈的交互都是通过接口,这就需要依赖注入,引入Dagger,但我不太喜欢在此种场景引入Dagger,从而带来额外的性能消耗,提升普及难度。
2.多ViewModel
按照1职能的拆分,我们已经能开开心心的设计代码了,但还是会很遗憾的发现,ViewModel中存放的LiveData及各种交互还是会很庞大,这就需要拆ViewModel,那么ViewModel的拆分规则是啥???有两种方案:
- 对应不同的xml拆不同的ViewModel
- 对应不同的Request拆不同的ViewModel
对应不同的xml拆不同的ViewModel
ViewModel的本职工作就是对视图的状态托管及管理,那么根据视图中拆分的xml规则来拆分viewModel没毛病。但是会有以下几个问题:
- 产品的心如女人难以琢磨,哪天来个UI调整....
- 多App复用性,假如你公司有几款产品,UI不一致导致ViewModel的复用性差
对应不同的Request拆不同的ViewModel
这是目前我采用的拆分方案,让ViewModel跟xml完全解耦,再也不怕产品改需求了,复用性也得到提升,修改后的整体方案如下:
![](https://img.haomeiwen.com/i7161394/1f0c0d1f9e3d72a8.png)
- UI层通过DetailPresenter持有的各种Request发送数据请求,发送的先后顺序由DetailPresenter自己控制。
- Domain层中Request中发起网络请求,获取结果后(如果需要的话可以做一些数据的转换),并透过LiveData分发回DetailPresenter中的订阅者。
- DetailPresenter中数据回来后,可以把数据设置给相对应的ViewModel中,ViewModel在驱动相应的视图更新数据。
3.补充
Lifecycle架构组件原理