android开发框架总结 (二)MVP与MVVM详细介绍与对比,如何选择适合的框架(干货!)

前言

本篇文章将非常“细致”地总结分析MVP与MVVM这两种框架对于架构的选择做了比较多的分析,应该是干货满满,如果你对这两者的使用与选择上还有迷惑之处。真的希望你能认真看完。

如果你是非常有经验的程序猿,那就当相互学习总结,如果有不同看法还望指教。当然,我也是非常想进步的。


目录

前言

1.MVP

MVP的优点

MVP的缺点

2.MVVM

MVVM的特点(优点)

MVVM的缺点

架构组件

3.MVP与MVVM的复用

4.如何选择

5.MVP+LiveData+ModeView+LifeCycle+Dagger2


1.MVP

文章的一开始,先来回顾一下,什么是MVP

MVP是在MVC的基础上进行改造,用Present解决了V与M之间耦合度的问题,activity是作为V层的。

View:对应于Activity/Fragment/自定义View,主要负责UI渲染。
Model:数据获取模块
Presenter: 负责数据处理以及View和Model的交互等,持有Model和View的引用。

在MVP模式中,View层只负责UI渲染,不再需要处理对应的业务逻辑,View层的量级大大轻化。而Presenter在获取到Model的数据,并进行处理后,通过View层暴露的接口调用去更新UI,这样View层和
Model层不互相持有引用,保证是隔离和解耦的。这样整个业务逻辑处理和视图的渲染是隔离的,就不会再出现上文提到的Activity/Fragment/View臃肿和混乱的问题。

我们来看一下MVP的结构图

 

 

当然,由于MVP比较多变,不同公司不同需求结构下P层可能会有比较多架构的变化。对于虚线部分,每个人的理解不同,情况不同,选择合适的就好,不用纠结谁对对错,本质不变就可以的。


MVP的优点

1.模型与视图完全分离

2.P层非常容易(适合)做单元测试

3.(Presener的复用)一个Presener可以用于多个视图(View),而不需要改变Presenter的逻辑。视图(View)的变化比模型(Model)的变化更频繁的多 ,所以这样超级方便。

4.(View的复用)View可以进行组件化。在MVP当中,View不依赖Model。这样就可以让View从特定的业务场景中脱离出来,可以说View可以做到对业务逻辑完全无知。它只需要提供一系列接口提供给上层操作。这样就可以做高度可复用的View组件。

5.可以更高效地使用Model,因为所有的交互都发生在一个地方——Presenter内部


MVP的缺点

1.Presenter层要处理的业务逻辑过多,复杂的业务逻辑会使P层非常庞大和臃肿。

2.Presenter中除了业务逻辑以外,还有大量的View->Model,Model->View的手动同步逻辑(没有做到像MVVM数据同步那样一劳永逸),造成Presenter比较笨重,维护起来会比较困难

3.接口及接口中声明的方法粒度不好把控。MVP的架构不是固定的,可能会随着实际需求的不同而有不同的改动。P层就是一个变化比较多的地方,P层的意义是使V与M层解耦。如果粒度太小,那么一旦业务多起来,我们的P层会非常臃肿。而如果粒度太大,那么我们一个P层确实可以达到复用,可却导致了我们不同需求的V层复用同一个P层接口时,要实现好多我们不需要的方法,这就是非常典型的违背了接口隔离,接口的实现类不应该实现没有的方法。而其中有些方法是否会用到以及是否会增加或删减还需要后续进一步确认。

4.Activity中需要声明大量跟UI相关的方法,而相应的事件通过Presenter调用相关方法来实现。两者互相引用和调用,存在耦合。一旦View层的UI视图发生改变,接口中的方法就需要改变,View层和P层同时都需要修改。


关于MVP的不足我也专门写了一篇文章从java基本原则 细数android中MVP的“七宗罪”

这里插个题外话

我觉得MVP设计的初衷应该是M V P三层分别有中间件衔接,三者分别负责不同类型的职责,三者本应该可由不同工程人员开发,并实现无缝衔接。三者中只有P层具有独立意志和决定权,V与M只是工具而已,V与M的替换应该是非常简单的。

可是实际中,涉及了UI逻辑的修改时,V与P耦合度并没有想象中那么低,V与P相牵连,都要配合着修改,这样P层被不是本职的工作所束缚。

Presenter虽然耦合大大降低,但是还是过于依赖Presenter

同时,MVP违背了当以职责原则,依赖倒置原则,接口隔离原则(如果粒度处理得当解决了这个问题),形式上解耦,但职责分工角度却耦合。

总的来说就是结构很清晰易懂,写起来不方便。

2.MVVM

首先了解一下,什么是MVVM

MVVM引入了VM层替代P层(ViewModel即 Model of View)它即包含了Modle也有View的状态。

MVVM模式中,一个ViewModel和一个View匹配,它没有MVP中的IView接口,而是完全的和View绑定,所有View中的修改变化,都会自动更新到ViewModel中,同时ViewModel的任何变化也会自动同步到View上显示。

这种自动同步的原因其实就是是ViewModel中的属性都实现了observable这样的接口,也就是说当使用属性的set的方法,都会同时触发属性修改的事件,使绑定的UI自动刷新。

在android中DataBinding帮助我们实现MVVM,在XML进行数据绑定,增加了XML的重量,不再像以前那样仅仅是布局,均衡了各部分的职责。

所以MVVM比MVP更升级一步,在MVP中,V是接口IView, 解决对于界面UI的耦合; 而MVVM干脆直接使用ViewModel和UI无缝结合, ViewModel直接就能代表UI.

我们来看下MVVM的结构图

MVVM的特点(优点)

1.相比于MVP,MVVM的UI做到了数据的双向同步,因此不需要像MVP那样手动编写特殊用例(打比方说MVP需要写个setInfo方法来请求数据,每次需要更新数据的时候都要调用这个方法。MVVM由于数据是同步的,只需要第一次将数据绑定UI就可以)所以当数据频繁更新时,MVVM就显得非常方便

2.ViewModel只负责提供数据给UI,处理Model的数据,不用持有V层的引用,而V层只负责监听数据,不处理任何与数据相关的逻辑。因此,当View层UI发生变化时,VM层不需要修改,而MVP中V层要大改时,有可能要同时改P层接口与V层实现方法

3.方便协作开发,V层与P层几乎不耦合,MVP中V层要实现P层接口的接口,而MVVM中,在V层使用组合(或者耦合度还可以更更低,使用Dagger2来解决V对VM的直接引用),由此来对其进行不同逻辑的。可以做到团队中一人负责UI,一人负责数据处理,并行开发。其实,vm不一定不可以持有v的引用,业务不同,可能会持有!

4.观察者模式:数据驱动,数据变->UI变,Model->View进行更新,VM只处理数据,V层只负责数据监听与UI与UI更新

5.易于单元测试(View层不能单元测试,当然,也没必要,因为View只负责UI绘制,不需要逻辑处理,所以V层代码越少越好)

数据复用,Respository模式下,VM层完全可以复用(MVP基本一个页面一个V一个P),多个模块对同一数据源,可以复用VM,改变V层即可

 

MVVM的缺点

1.View层采用DataBinding,xml文件的bug不好定位(不是java语音,没有log)

2.大模块中,model层会很大。这种情况下,虽然请求到的数据保持一致性,但是由于长时间持有不释放,比较占内存

3.数据双向绑定,不利于代码复用,由于View层取到的数据是双向绑定的,一个View只能对应一个model(View中必须声明绑定的是那个VM层的方法,一个方法对应一个model),不同模块间model不同,View不能复用,View层不能复用。View的复用还是比较重要的

随着Google官方推出的一系列架构组件,也大大推动了MVVM的流行。

架构组件

LifeCycle:可以让控件监听Activity或Fragment的生命周期,也就是V层不用处理生命周期需要处理的业务逻辑,更专心做UI绘制

WorkManager:调度任务,让任务异步,以及决定何时执行,执行顺序(可实现链式任务)

LiveData:感知Fragment与Activity的生命周期(可能内部也涉及了LifeCycle,不太了解)的数据容器,数据一旦改变就通知UI进行界面更新。当Act组件生命周期结束时会销毁(会占着内存不放,当数据很多时不太好就是)

ViewModel:1.将视图的数据与逻辑从有生命周期的组件中剥离,旋转屏幕导致Act重建时数据仍会存在,直到Act完全销毁VM菜消失(可以取代OnSaveInstance了)2.用来在act与fra中数据共享(不用使用接口或者是EventBus了)3.防止内存泄露(act已经退出,异步任务还在执行)4.act中只应该处理用户的交互和UI展示,数据处理工作可以由VM来做

现在的MVVM多是采用了DataBinding+ViewModel+LiveData的结构

这里上使用了架构组件的MVVM代码  ,这种结构的好处相信大家通过上面架构组件和MVVM结构的介绍也有一定了解了。

3.MVP与MVVM的复用

MVVM中,M层与MV层可以复用,View不行

MVP中,情况就比较复杂了

目前大多数开发人员使用的MVP架构模型,基本都是“变种”,为的是减少开发成本,提高编码速度,比如:P层和M层合到一起,也就是“网络请求(M层)”放入到P层来做。从开发长远角度来考虑,这种方式并不理想,比如一个接口的网络请求多次使用,这个时候就要在P层多次书写,用标准式,就解决了这个问题,可以用M层来复用解决这个问题。

4.如何选择

大项目用MVP是一个不错的主意,V层M层可以复用。P层方便做单元测试,同时P层的接口可以使在一开始对后续编码的过程有一个整体的把控,接口使得代码逻辑性非常强(这点两点很重要)。M与V并行开发,在大项目中,Model层不会像MVVM那样占着内存不释放View也可以复用(不过个人还没遇到View可以比较多复用的情况,希望大家补充)。同时View层的bug不像使用了DataBinding那样的MVVM难以排查

小项目MVVM更合适,频繁的需求更新,不会像MVP那样P层无法复用V层只需处理UI绘制(绑定数据,甚至不用实现接口)。VM+LiveData模式下,解决了UI不活跃时候出现空指针的问题没有P层太大的问题(接口太多)。View层与VM层是组合的关系,不像MVP那样需要实现接口。
 

MVP在大的项目中的使用相对还是比较得心应手的,但是,如果你的项目不大,并且由一个人开发。你强行使用MVP,那么你项目的前期可能得重复写好多接口,这很让人头大。

5.MVP+LiveData+ModeView+LifeCycle+Dagger2

相比MVP,MVVM在某些方面更加友好,其实好多有经验的工程师,更倾向于在MVP与MVVM之间取得一个折中。

这里我们来对两者进行优化。

一种比较优雅的写法是MVP+LiveData+ModeView+LifeCycle+Dagger2。这里附上了源码。后续会在写一篇文章来讲解这种华丽的结构,欢迎相互学习与探讨,如果有不同看法,请不吝赐教,相互进步!
 

本文重在分析讲解android框架的选择,下一篇文章将会着重分析如何对其进行优化。

猜你喜欢

转载自blog.csdn.net/qq_39037047/article/details/84726290