Android 架构系列:
Android 架构一:Android 架构浅析
Android 架构二:纵向横向结合构建项目
Android 架构三:组件化思想
Android 架构四:组件化架构实战
Android 架构五:MVVM+Data Binding构建项目
……
一、前言
我们都知道,Web的架构经过多年的发展已经非常成熟了,我们常用的SSM,SSH等等,架构都非常标准。个人认为,Web服务逻辑比较清晰,目的明确,流程也相对固定,从服务器收到请求开始,经过一系列的的拦截器,过滤器->被转发到控制器手中->控制器再调用服务->服务再调用DAO获取想要的数据->最后把数据返回给web层。哪怕中间增加一些东西,如缓存什么的。他的模型依然是以用户请求的线程为生命周期,经过一个个切面(层)的结构,感觉类似于流水线的结构吧。
而Android App则有所不同,他没有像用户请求这样一个统一的出发点,最接近的可能是来自于UI的事件,然而远不仅仅于此。根据app不同的需求,其结构也会千差万别,所以很难有较为统一的架构。
但是客户端类app确实是较为常见的App类型,其结构还是有迹可循的。
我们知道,Android 常见架构有MVC、MVP和MVVM,还有最近非常流行的组件化就是指将应用根据业务需求划分成各个模块来进行开发,每个模块又可以编译成独立的APP进行开发。理论上讲,组件化和前面三种架构设计不是一个层次的。它们之间的关系是,组件化的各个组件可以使用前面三种架构设计。
我们只有了解了这些架构设计的特点之后,才能在进行开发的时候选择适合自己项目的架构模式。
下面,我们就来了解一下,这几个架构吧。
二、MVC
1、MVC定义
MVC (Model-View-Controller, 模型-视图-控制器),标准的MVC是这个样子的:
- 模型层 (Model):业务逻辑对应的数据模型,无View无关,而与业务相关;
- 视图层 (View):一般使用XML或者Java对界面进行描述;
- 控制层 (Controllor):在Android中通常指Activity和Fragment,或者由其控制的业务类。
2、MVC架构优缺点
Activity并非标准的Controller,它一方面用来控制了布局,另一方面还要在Activity中写业务代码,造成了Activity既像View又像Controller。
在Android开发中,就是指直接使用Activity并在其中写业务逻辑的开发方式。显然,一方面Activity本身就是一个视图,另一方面又要负责处理业务逻辑,因此逻辑会比较混乱。
这类App一般会定义一个BaseActivity,BaseActivity内部实现了网络的异步请求,本地数据的存储加,数据库访问载等复用性较强的逻辑。逻辑控制则在对应的Activity中实现。
Activity过于臃肿,往往一个Activity成千上万行代码。View层的XML控制力其实非常弱,众多的View处理还是要放在Activity进行,这样的话,Activity就既包含了View又包含了Controller,耦合高,不利于测试扩展,可读性也变差。
所以,这种开发方式不太适合Android开发。
三、 MVP
1、MVP定义
MVP (Model-View-Presenter) 是MVC的演化版本,几个主要部分如下:
- 模型层 (Model):主要提供数据存取功能。
- 视图层 (View):处理用户事件和视图。在Android中,可能是指Activity、Fragment或者View。
- 展示层 (Presenter):负责通过Model存取书数据,连接View和Model,从Model中取出数据交给View。
所以,对于MVP的架构设计,我们有以下几点需要说明:
- 这里的Model是用来存取数据的,也就是用来从指定的数据源中获取数据,不要将其理解成MVC中的Model。在MVC中Model是数据模型,在MVP中,我们用Bean来表示数据模型。
- Model和View不会直接发生关系,它们需要通过Presenter来进行交互。在实际的开发中,我们可以用接口来定义一些规范,然后让我们的View和Model实现它们,并借助Presenter进行交互即可。
实际上,MVP的原理就是View通过Presenter获取数据,获取到数据之后再回调View的方法来展示数据。
2、MVC 和 MVP 的区别
- MVC 中是允许 Model 和 View 进行交互的,而MVP中,Model 与 View 之间的交互由Presenter完成;
- MVP 模式就是将 P 定义成一个接口,然后在每个触发的事件中调用接口的方法来处理,也就是将逻辑放进了 P 中,需要执行某些操作的时候调用 P 的方法就行了。
4、MVP的优缺点
优点:
- 降低耦合度,实现了 Model 和 View 真正的完全分离,可以修改 View 而不影响 Modle;
- 模块职责划分明显,层次清晰;
- 隐藏数据;
- Presenter 可以复用,一个 Presenter 可以用于多个 View,而不需要更改 Presenter 的逻辑;
- 利于测试驱动开发,以前的Android开发是难以进行单元测试的;
- View 可以进行组件化,在MVP当中,View 不依赖 Model。
缺点:
- Presenter 中除了应用逻辑以外,还有大量的 View->Model,Model->View 的手动同步逻辑,造成 Presenter 比较笨重,维护起来会比较困难;
- 由于对视图的渲染放在了 Presenter 中,所以视图和 Presenter 的交互会过于频繁;
- 如果 Presenter 过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密,一旦视图需要变更,那么Presenter也需要变更了。
综上,虽然MVP是在MVC的基础上演变而来,并且大大缓解了在Android上的Controller过于庞大的问题,但是,它并不是Android APP的最理想的架构,于是,就引出了下面的 MVVM 机构。
四、MVVM
1、定义
MVVM 是 Model-View-ViewModel 的简写。它本质上就是 MVP 的改进版。MVVM 就是将其中的 View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。
- 模型层 (Model):负责从各种数据源中获取数据;
- 视图层 (View):在 Android 中对应于 Activity 和 Fragment,用于展示给用户和处理用户交互,会驱动 ViewModel 从 Model 中获取数据;
- ViewModel 层:用于将 Model 和 View 进行关联,我们可以在 View 中通过 ViewModel 从 Model 中获取数据;当获取到了数据之后,会通过自动绑定,比如 DataBinding,来将结果自动刷新到界面上。
使用 Google 官方的 Android Architecture Components ,我们可以很容易地将 MVVM 应用到我们的应用中。
2、MVVM与MVP区别
我们再来看看MVP的原理
由两者的原理图,可以看到 ViewModel 承担了 Presenter 中与 view和 Model 交互的职责,与 MVP模式不同的是,VM与 V 之间是通过 Datebingding 实现的,而 P是持有 View 的对象,直接调用 View 中的一些接口方法来实现。
ViewModel可以理解成是View的数据模型和Presenter的合体。它通过双向绑定(松耦合)解决了MVP中Presenter与View联系比较紧密的问题。
3、MVVM 的优点和缺点
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),它有以下优缺点。
优点:
- 低耦合:视图(View)可以独立于Model变化和修改,一个 ViewModel 可以绑定到不同的 View 上,当 View 变化的时候 Model 可以不变,当 Model 变化的时候 View 也可以不变。
- 可重用性:你可以把一些视图逻辑放在一个 ViewModel 里面,让很多 view 重用这段视图逻辑。
- 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。
- 可测试:界面素来是比较难于测试的,而现在测试可以针对 ViewModel 来写。
缺点:
- 1、数据绑定使得 Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。不过,貌似google最新推出的data binding已经解决该问题,待尝试。
- 2、一个大的模块中,model也会很大,虽然使用方便了也很容易保证了数据的一致性,当长期持有,不释放内存,就造成了花费更多的内存。这个问题都不大,其实没有必要把一个超级大模块的数据都整合到一个面面俱到的model, 我们可以把巨型模块拆分成若干小模块,这也符合高内聚低耦合的设计思想。
- 3、数据双向绑定不利于代码重用。客户端开发最常用的重用是View,但是数据双向绑定技术,让你在一个View都绑定了一个model,不同模块的model都不同。那就不能简单重用View了。
五、MVC、MVP与MVVM的关系
MVVM可以算是MVP的升级版,其中的VM是ViewModel的缩写,ViewModel可以理解成是View的数据模型和Presenter的合体,ViewModel和View之间的交互通过Data Binding完成,而Data Binding可以实现双向的交互,这就使得视图和控制层之间的耦合程度进一步降低,关注点分离更为彻底,同时减轻了Activity的压力。
我们对比一下三者的原理图,看看他们的异同
刚开始理解这些概念的时候认为这几种模式虽然都是要将view和model解耦,但是非此即彼,没有关系,一个应用只会用一种模式。后来慢慢发现世界绝对不是只有黑白两面,中间最大的一块其实是灰色地带,同样,这几种模式的边界并非那么明显,可能你在自己的应用中都会用到。实际上也根本没必要去纠结自己到底用的是MVC、MVP还是MVVP,不管黑猫白猫,捉住老鼠就是好猫。
1、MVC->MVP->MVVM演进过程
MVC -> MVP -> MVVM 这几个软件设计模式是一步步演化发展的,MVVM 是从 MVP 的进一步发展与规范,MVP 隔离了MVC中的 M 与 V 的直接联系后,靠 Presenter 来中转,所以使用 MVP 时 P 是直接调用 View 的接口来实现对视图的操作的,这个 View 接口的东西一般来说是 showData、showLoading等等。M 与 V已经隔离了,方便测试了,但代码还不够优雅简洁,所以 MVVM 就弥补了这些缺陷。在 MVVM 中就出现的 Data Binding 这个概念,意思就是 View 接口的 showData 这些实现方法可以不写了,通过 Binding 来实现。
同
如果把这三者放在一起比较,先说一下三者的共同点,也就是Model和View:
Model:数据对象,同时,提供本应用外部对应用程序数据的操作的接口,也可能在数据变化时发出变更通知。Model不依赖于View的实现,只要外部程序调用Model的接口就能够实现对数据的增删改查。
View:UI层,提供对最终用户的交互操作功能,包括UI展现代码及一些相关的界面逻辑代码。
异
三者的差异在于如何粘合View和Model,实现用户的交互操作以及变更通知
- Controller
Controller接收View的操作事件,根据事件不同,或者调用Model的接口进行数据操作,或者进行View的跳转,从而也意味着一个Controller可以对应多个View。Controller对View的实现不太关心,只会被动地接收,Model的数据变更不通过Controller直接通知View,通常View采用观察者模式监听Model的变化。
- Presenter
Presenter与Controller一样,接收View的命令,对Model进行操作;与Controller不同的是Presenter会反作用于View,Model的变更通知首先被Presenter获得,然后Presenter再去更新View。一个Presenter只对应于一个View。根据Presenter和View对逻辑代码分担的程度不同,这种模式又有两种情况:Passive View和Supervisor Controller。
- ViewModel
注意这里的“Model”指的是View的Model,跟MVVM中的一个Model不是一回事。所谓View的Model就是包含View的一些数据属性和操作的这么一个东东,这种模式的关键技术就是数据绑定(data binding),View的变化会直接影响ViewModel,ViewModel的变化或者内容也会直接体现在View上。这种模式实际上是框架替应用开发者做了一些工作,开发者只需要较少的代码就能实现比较复杂的交互。
一点心得
MVP和MVVM完全隔离了Model和View,但是在有些情况下,数据从Model到ViewModel或者Presenter的拷贝开销很大,可能也会结合MVC的方式,Model直接通知View进行变更。在实际的应用中很有可能你已经在不知不觉中将几种模式融合在一起,但是为了代码的可扩展、可测试性,必须做到模块的解耦,不相关的代码不要放在一起。
个人理解,在广义地谈论MVC架构时,并非指本文中严格定义的MVC,而是指的MV*,也就是视图和模型的分离,只要一个框架提供了视图和模型分离的功能,我们就可以认为它是一个MVC框架。在开发深入之后,可以再体会用到的框架到底是MVC、MVP还是MVVM。
五、组件化
所谓的组件化,通俗理解就是将一个工程分成各个模块,各个模块之间相互解耦,可以独立开发并编译成一个独立的 APP 进行调试,然后又可以将各个模块组合起来整体构成一个完整的 APP。它的好处是当工程比较大的时候,便于各个开发者之间分工协作、同步开发;被分割出来的模块又可以在项目之间共享,从而达到复用的目的。组件化有诸多好处,尤其适用于比较大型的项目。
由于篇幅以及组件化区别以上其它三种架构,它是一中横向分块的思想,我将单独一节来讲讲组件化。
六、总结
MVC、MVP和MVVM各有各自的特点,可以根据应用开发的需要选择适合自己的架构模式。组件化的目的就在于保持各个模块之间的独立从而便于分工协作。它们之间的关系就是,你可以在组件化的各个组件中应用前面三种架构模式的一种或者几种。
`