MVP+RxJava是最近一两年讨论最热的技术,也许你最近还在讨论他们?
via @Hanna Jung in Dribble.
我们了解这种架构模式并且已经运用到实际项目中了,但是我们真的能在该架构模式下获得高效的利益吗?MVP和RxJava库能为用户带来价值吗或者能帮助开发者提升迭代速度吗?
我们都知道MVP能带来两方面的好处:
- 简洁的代码
- 完全可测试的业务逻辑
这就是为什么使用MVP+RxJava,因为基于以上两点我们可以在未来的迭代中更加快速。
架构背景
首先在我们对架构知识理解的基础上对代码逻辑分为三(或者更多)层:
- 数据层(Data):负责从磁盘、网络或者其他实体提供数据。例如,用户位置信息、服务器数据等
- 领域层(Domain):通常在该层编写可复用的业务逻辑代码来用于数据层和UI层的交互。例如,对位置信息做一些操作等
- UI层(或者描述层Presentation):界面显示或者用户交互的直接目标。例如,一个按钮的点击等行为
架构分层
在上图的分层中,对于数据层来说,应该保有高百分比可测试性的代码,我们通常不对网络或者存储类进行测试;对于领域层应该是可100%测试的代码;最大的挑战是对UI层代码的测试。
有了对分层架构的基本认识后,我们需要将MVP引入到分层中:
MVP is a pattern used only in the UI layer.
将大量的业务逻辑从UI层移到Presenter层,并且归为相应的类文件,这样也有利于单元测试。
那么,RxJava呢?
RxJava is a library to have these 3 layers communicate with each other.
有了以上知识,我们使用MVP来创建一个UI层的逻辑:
描述层
首先第一步需要清楚将要与用户交互的View都有哪些视图状态。我们不需要关心视图是什么(Activity、Fragment、View 等)因为我们只需要调用接口(StateView)就能完成。
通用的MVP框架
在描述层要定义的动作最少应该有两个,一个是start一个是stop。对于StateView来说可以随着状态的变化而动态更新。视图状态决定当前视图所显示的内容。
Presenter.java
StateView.java
实现
首先,我们启动一个Presenter,Presenter将会收到所有在领域层需要观察的Rx observables并且更新相应的视图。例如检查用户是否登陆
|
|
接着,转换数据并且判断视图状态做相应的视图变化:
|
|
最后,我们在onStart中启动并且更新视图
|
|
当我们停止一个Presenter时,我们需要注销相应的被观察者以防止内存泄漏。
整个代码如下:
|
|
测试
FilterButtonPresenterTest.java
UI层
使用已经定义好的视图状态类来更新相应的UI组件。
FilterButtonActivity.java
这里出现一个问题值得我们深思,我们是要在Activity的相应生命周期中调用Presenter的start和stop吗?还是其他时机也需要调用?
如果我们只是简单的在onStart/onDestroy生命周期中调用start和stop,但我们的activity异常退出怎么办?onSaveedInstance要不要调用相应的状态保存呢?这些事情是很头疼的。再如设备开启了接电保护后,我们不希望在onStop后的Activity中一直运行Presenter的action,那么我们就需要在onStop中执行presenter.stop()。
进一步说明
- 当计划使用MVP时,一定要把握好视图的可能出现的状态。
- 如果你要开发一个全部交互的app,那么数据层与领域层以及领域层与UI层都要使用RxJava库来进行通信。这样也比使用从数据层的视图状态来更新UI层的方式更加简单
- 如果定义两个或者两个以上不同的Presenter时需要清楚UI的状态(例如, 用户从一个ListView中选择一个Item并你想同时更新两个不同的UI),那么建议使用视图状态来动态更新UI
- 有些情况基于用户与UI界面的交互我们需要更新领域层或者数据层的信息,简单的可以在Presenter中添加相应的方法,在UI交互的时候调用这些方法。