首页 存档 技术 查看内容

Android架构(一)MVP架构在Android中的实践

2018-3-30 13:00 |来自: 互联网 339 0

摘要: 本文来自于CSDN博客,作者:余志强,已获授权,版权归原作者所有,未经作者同意,请勿转载。欢迎同有博客好文章的作者加微信(ID:tm_forever_miss)或直接邮件([email protected])投稿、约稿、给文章纠错。 为 ...

本文来自于CSDN博客,作者:余志强,已获授权,版权归原作者所有,未经作者同意,请勿转载。

欢迎同有博客好文章的作者加微信(ID:tm_forever_miss)或直接邮件([email protected])投稿、约稿、给文章纠错。

为什么要重视程序的架构设计

对程序进行架构设计的原因,归根结底是为了提高生产力。通过设计是程序模块化,做到模块内部的高聚合和模块之间的低耦合(如依赖注入就是低耦合的集中体现)。

这样做的好处是使得程序开发过程中,开发人员主需要专注于一点,提高程序开发的效率,并且更容易进行后续的测试以及定位问题。

但是,设计不能违背目的,对于不同量级的工程,具体的架构实现方式必然不同,不要为了设计而设计,为了架构而架构。比如一个Android app如果只有几个Java文件,那只需要做点模块和层次的划分就可以了。引入框架或者架构增加了工作量,降低了生产力。

所以在开发的时候需要考虑:

1)当前这个项目是否需要以最快速度上线。比如有些创业公司,争取的就是时间,公司老板是要拿着这个app是去找投资的。

2)如果这个项目开发周期还可以,第一个版本就可以把app架构做好。因为一个App肯定是朝着慢慢做大的方向去的,如果等业务到了一定程度了,再去重构的话,成本就有点大。

什么是MVP?

MVP架构由MVC发展而来。在MVP中,M代表Model,V代表View,P代表Presenter。

Model 负责获取数据,数据的来源可以是网络或本地数据库等;

View 负责界面数据的展示,与用户进行交互;

Presenter 是Model与View之间的通信的桥梁,将Model与View分离开来。

MVP架构图:

所以MVP的架构有如下好处:

1)降低了View和Model的耦合,通过Presenter层来通信;

2)把视图层抽象到View接口,逻辑层抽象到Presenter接口,提高了代码的可读性、可维护性;

3)Activity和Fragment功能变得更加单一,只需要处理View相关的逻辑;

4)Presenter抽象成接口,就可以有多种实现,方便单元测试。

下面就来实际的体验一下MVP在项目中的使用吧!(用户注册和文章详情两个例子)

用户注册

Model部分

View

Presenter

上面的代码有详细的注释,方法名定义的也比较形象,一看就知道干什么的。

如果明白了MVP架构的流程图,上面的代码虽然有点长,但是非常很好理解:

Activity 实现了ILoginView接口,所以Activity就是View 层;

Model层呢,在这里就是请求网络。

我们并没有让Activity和Model直接交互,而是通过Presenter层来作为沟通桥梁的。

所以Activity里组合了Presenter:

在Presenter中组合了ILoginView

这样Presenter和View之间包含了彼此,就可以彼此通信了。这样就把Activity(View) 和 Model之间实现了低耦合。

使用MVP架构需要注意的地方

1)释放资源(在用户离开界面的时候,记得释放Presenter的资源)

2)方法命名/有些方法应该放在IView接口里还是接口的实现者Activity里的问题

我也看了其他一些MVP的例子,很多也是基于登录的例子,比如在登录成功后,跳到主界面,在IView接口定了 goMain()或goMainActivity() 我觉得这样是不妥的。

假设用户登录成功后的逻辑变了,不跳到主界面了而是其他的逻辑了,那在ILoginView顶层接口里定义goMain()或goMainActivity()就不合适了,因为用不到了,总不能在goMain方法里不写跳到主界面而是写其他代码的逻辑吧,这样方法名和里面的代码就不匹配了。如果更改方法名,那所以实现该接口的类都需要改方法名了,耦合又变大了。

我的建议是,既然是登录成功的逻辑,那就在ILoginView接口里定义loginSuccess()方法,不管以后登录成功做什么逻辑都可以在loginSuccess()里实现。而不应该直接把业务逻辑和方法名绑定死了,并且还把绑定死的方法名放在ILoginView顶层接口里,因为业务逻辑是很容易发生变化的。所以应该定义一个通用的方法名loginSuccess()。

有人说goMain()或goMainActivity(),你看多清晰,一看我就知道是干什么的。但是loginSuccess()不知道做什么逻辑,还得详细看loginSuccess()里的代码。 我觉得考虑的也有一定的道理,但是这不能作为把业务逻辑和方法名绑定死了放到顶层接口里的理由。
如果你出于这种考虑也很好解决的,直接在实现ILoginView的Activity里定义 goMain() 或 goMainActivity() 方法,然后在loginSuccess()里调用goMain()或goMainActivity()。

3)有些代码可以放在Activity又可以放到Presenter,该怎么抉择?

我们在使用验证码注册的时候,当用户点击获取验证码的时候,开发者可能就下意识的就在在Activity中调用SMSSDK的API来获取验证码,然后在Activity中处理获取成功和失败的逻辑。

乍一看功能实现没问题,我们可以在Activity中调用SMSSDK的API来获取验证码,也可以在Presenter里调用SMSSDK的API来获取验证码。在使用MVP架构的时候我们时常遇到这样的抉择,在哪里写都可以实现功能,我们该怎么抉择呢?

其实这个时候SMSSDK(只不过SMSSDK是第三方提供的API而已)就是充当着Model的角色,因为SMSSDK就是去请求网络,然后发送验证码的,如果我们直接在Activity(View)中调用了,那么Model和View又耦合了,所以应该放在Presenter中来做。假设有一天发送验证码的SDK我们替换成了其他第三方的SDK了,在View层我们不需要修改一行代码,只需要修改Presenter就可以了。

通过上面一个登录的例子,有些读者看到接口中这么多方法,瞬间感觉这个MVP不仅没有帮我们解决问题,反而是问题的制造者。不是这样的!假设我们使用熟悉的MVC开发的时候,我们可能是这样的实现的:

上面的代码直接Activity中操作Model,耦合变得比较大了。而且随着业务的增多Activity的代码会越来越臃肿。

其实MVP也就是在上面的代码之上做出一些改良而已,上面我们在View中直接操作Model,现在呢?MVP只不过是View和Model不直接通信了,通过Presenter来通信,Activity(View)操作Presenter,Presenter来操作Model,这样View和Model实现了间接的通信了。

聪明的读者可能又有问题了,分层(View、Presenter)可以啊,但是也不至于每层都设计一个接口吧?那么以接口的形式给我们带来什么好处了呢?

1)代码更加清晰

这样在一定程度上避免了开发者在一个方法里有太多的代码,因MVP强制要求把各个业务都封装在方法里然后调用。

2)做好业务的顶层设计

在开发的时候,当产品原型出来通过了评审后,因为业务都出来了嘛,开发这块就可以把View、Presenter接口的各个函数名全部设计好,做好顶层设计,这也倒逼开发者对这个需求这块一定要有着全面的理解。如果对业务不了解是无法设计出接口的。到时候往方法里填代码就可以了。

3)解耦

我想大家应该注意到了,在View一层我们使用Presenter的时候都是通过IPresenter接口来定义的,而不是该接口的实现着。这样做方便后面替换,这也是面向接口编程的好处。到时候业务逻辑变了,我们只要重新实现IPresenter接口,然后在View中替换下IPresenter的实现者即可,而View层不需要修改代码。

MVP模式实现文章详情

如果对上面的注册的例子理解了,实现这个功能就非常简单了。由于篇幅的原因,具体的代码细节就不帖胡扯了。把代码的接口设计出来。

该界面主要有加载文章、评论列表、评论、分享等功能。

是不是很简单,只要把顶层的接口设计出来,接下来就是在方法里填代码就可以了。

以上就是我对MVP架构的实践与理解,如果有任何问题或者有更好的建议欢迎留言讨论。

了解最新移动开发、VR/AR 干货技术分享,请关注 mobilehub 微信公众号(ID: mobilehub)。

本文转载于微信公众号: mobilehub(mobilehub),更多微信文章请扫描关注公众号:

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部