为了账号安全,请及时绑定邮箱和手机立即绑定

Android MVP 架构设计之美

我们经常在讨论Android的架构,MVC,MVP,或者MVVM,有些同学觉得架构好App就做得好,其实这是错误的,我们归根结底还是需要找到自己合适的架构,适合自己的才是最好的,所以如何选择适合自己的架构才是关键。

《银河补习班》中有一句话:人生就像射箭,梦想就像箭靶子,如果连箭靶子也找不到的话,你每天拉弓有什么意义?”

图片描述

你得先了解你的需求,你的功能,你的可扩展方向,你才能知道,哪个架构适合你,同样你也要了解这些架构的优点,缺点,以及痛点,MVC能用这么久必然有它的道理,很多人舍弃MVC转而去使用MVP也必然有它的道理,既然里面这么多问题,这么多道道,我们想深度的了解,那么就需要刨根问底了。

先来说说MVC吧,分解出来,就是Model,ViewController对吧,再转换一下就是模型视图控制器了,Model我们可以不用理会,主要来看下视图和控制器,控制器我们可以换一种说法,也就是逻辑,那么可以总结出:MVC就是视图与逻辑分离,再精简一下,View就是我们的XML,而逻辑就是我们的Activity或者Fragment等类,这样就好理解了吧,他们的分工是明确的,布局就负责UI,Activity就负责逻辑。

这套架构沿用了几十年,也深受各界的爱戴,然而随着互联网乃至IT界的高度发展,需求越来越多,代码越来越多,项目也越来越大的情况下,你会发现,哪怕你写得代码再美,再精简,各种管理类,帮助类,特别是Activity,异常的臃肿,几千行都不叫事儿,我上万行的都见过… ,而且你会发现一个问题,虽然架构叫MVC,但是View其实能做的工作特别少,各种控件的赋值,操作都是在Activity中完成的,倒不如干脆叫MC构架?(大家好,我是MC喜洋洋,青青草原我最狂~)

这个时候工程师们就意识到了,必须去做一些改变了,将逻辑层进行解耦,所以我现在回头看看MVP,你就明白他是干什么的了。

那么我们说到MVP,首先依旧是分解它,Model,View,以及Presenter ,你会发现,与MVC来讲,一个是C一个是P,也就是,模型视图接口层,P的职责就是连接View和Model并且对业务逻辑进行处理,相当于一个中转,Model将数据处理好之后通过Presenter传递给View去更新UI。

按照百度百科的说法:MVP是从经典的模式MVC演变而来,它们的基本思想有相通的地方 :Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

所以按照我们正常的开发思维,MVC就如图中所示:

图片描述

当Model的值更改,则需要通过Controller去通知View修改,因为View是依附在Activity中,如果View发生更改,同样的会更改Activity的监听去修改Model的值,同样的,View中是持有Model的引用的,Model中也有View的引用控制,这样的话,显而易见,他们互相是可以调用的,首先不说这个架构是不是比较乱,单从互相引用来看,过程中的问题肯定会出现很多。

那么再来看下MVP,既然说MVP是MVC的变种,那么他是如何修复这种弊端的呢?我们来看下图片:

图片描述

比较明显的两个不同点,首先是Controller替换成了Presenter,而Model与View则无法通信,所以一般其他道友总结会这样去画图:

图片描述

所以MVP首当其冲的就是Model与View的解耦,其次就是Activity的解耦了,P作为桥梁去平摊Activity的逻辑,让Activity做到真真正正认认真真的只负责View视图显示,这个怎么理解呢?首先P持有M这个没问题吧,那么现在P需不需要持有View,也就是P与Activity的通信如何去通信,这里则需要使用到接口了,也就是ActivityInterface,P与V之间通过接口进行通信就很好的实现了他们之间的解耦了,而ActivityInterface是一个新名词,所以我们重新来梳理一下他们关系,这也是很多人学MVP搞不懂的地方,关于MVP的角色关系。

  • View 视图 可以理解为Activity/Fragment
  • ActivityInterface 视图接口,便于View与Presenter之间的交互
  • Presenter 作为View与Model之间的通信桥梁
  • Model 数据层

所以,注意呀,MVP会多一个接口角色,当然,有些人会给Model也写一些接口来解耦,这也是可以的。

那么长篇文字的赘述下,你是否有一些理解他们之间的区别了呢?不了解也没关系,现在还没到让你总结他们的优缺点以及对比的时候,现在开始进入实战吧,我们通过代码来理清楚这些逻辑岂不是印象更深刻?

“清华北大只是过程,不是目的”。面对儿子的长大后想干什么的回答,马皓文想让他知道,能读清华北大的人毕竟是少数,即使没有考上清华北大,人生也要有追求的目标,毫无目标的生活,就如没有箭靶子一样,每天拉弓就没有意义。

图片描述

同样的,MVP也并不是什么新技术,更多的是思考以及开发思路的转变,我们来做一个很简单很简单的例子吧。

需求:通过OkHttp请求一个Url,通过Gson转换数据,Glide显示图片,RecyclerView显示数据

那么我们先来看下传统的MVC写法是如何实现的:

先说思路吧:先创建一个实体Bean,再创建一个Adapter,然后在Activity中初始化RecyclerView后,通过OkHttp请求数据后,填充到Adapter中,所以我们先看下实体类

图片描述

我们只需要取ResultBean中的几个数据即可,再来看下Adapter

图片描述

在适配器中,其实没什么特别,在onBindViewHolder中填充Bean的数据就是了,然后再来看下Activity的代码:

图片描述

这是一份很简单的代码,人人都会,那么从中你可以看出MVC相关相关的逻辑吗?首先Model就是MvpRecyclerBean,这可以理解吧,然后就是View了,View的话你可以理解为布局,再看Controller,实际上在MVC的体系中他就相当于我们这个Demo中的MainActivity了,你可以发现,他们的关系就是相互的穿插。

图片描述

通过这张图就可以反映出来。

我们也可以看下效果:

图片描述

那么我们现在通过Mvp来进行优化,是如何去做的呢?

其实代码本身很简单,更多的是将传统的MVC思路给转换,架构体现的就是思想,我也尽量的通过语言来一直解释其中缘由,如果只是抛出代码,实际上没多少东西,但是你学完你也会发现,也没学到多少东西,所以吾日三省吾身,思路,思想,思考

MVP的核心就是将UI逻辑抽象成View接口,将业务逻辑抽象成P的接口来体现,我们来看下这张图:

图片描述

View通过接口向P获取数据,实际上P是向M获取数据,M获取到数据之后通过接口给P,P来处理后,告知View的UI逻辑。

你会发现,M和V是无法直接接触的,他们中间有P作为中转,很好的做到了各自的职责,那么我们来看下代码怎么改吧:

先来看下我创建的包名:

图片描述

我们可以看到,我创建了model包下的两个类,分别是MainModel的实现以及IMainModel的接口实现,还有MainPresent的中转实现以及IMainView的UI视图实现。

再来看一张图:

图片描述

这是MVP的核心思想,一定要仔细看,先说逻辑再说代码,首先,在MainActivity中会去创建MainPresent的实例,这样就可以调用MainPresent的loadData方法加载数据了,在MainPresent的loadData中实际上是创建了MainModel,通过MainModel来调用他的loadData加载数据,然后MainModel作为一个执行者去通过OkHttp拉取到数据之后通过IMainModel接口的OnResultListener返回给MainPresent,MainPresent又通过IMainView的showRecyclerview接口返回给MainActivity,然后MainActivity即更新UI即可。这逻辑多读几遍,然后来看代码:

第一步:在MainActivity中会去创建MainPresent的实例,这样就可以调用MainPresent的loadData方法加载数据了

图片描述

第二步:在MainPresent的loadData中实际上是创建了MainModel,通过MainModel来调用他的loadData加载数据

图片描述

第三步:MainModel作为一个执行者去通过OkHttp拉取到数据

图片描述

第四步:之后通过IMainModel接口的OnResultListener返回给MainPresent

图片描述

第五步:MainPresent又通过IMainView的showRecyclerview接口返回给MainActivity

图片描述

第六步:然后MainActivity即更新UI即可

图片描述

前后呼应,我已经把功能和代码完全解析了一遍,你只要认真读,学会不成问题,那么你现在可以发现,我们一共创建了四个类,要是加上MainActivity就五个类了,MainActivty全部通过Present去操作逻辑,而数据层则是通过P绑定的Model层来做的,这样你是不是有一种豁然开朗的感觉,没错,结合我们之前画的图,你理解就更加透彻了。

当然,如果你想增加更多的接口,比如showLoding,或者showErrorDialog什么的也是没问题的,在IMainView中增加即可,然后在Present中实现就好了。

写完这些代码之后你会不会产生疑惑,使用MVC我只要把OkHttp请求数据的代码块直接放在Activity,然后得到结果显示就好了,但是用了MVP你却让我这个转那个转这个的,这就涉及到了MVC和MVP的优缺点了

  • 1.MVC和MVP都有自己的优势和劣势
  • 2.小项目优先MVC,大项目优先MVP
  • 3.MCV会让Activity十分的庞大,代码难懂
  • 4.MVP可以分解单一职责,代码易懂,却增加了很多的类和接口
  • 5.MVP高度解耦

接下来还有最后一个问题,关于内存泄漏的问题。

关于内存,我在之前的内存泄漏中告诉过大家如何去解决此类问题,这里就不一一赘述了,我们直奔主题吧。

MVP的优点很多,得益于P的思路转变,但是由于P是持有View和Model的引用,那么如果View,也就是Activity退出没有及时销毁,而P或者M都有可能在异步执行,这个时候内存肯定会出现泄漏乃至溢出的风险,那解决的办法也很简单,当Activity销毁的时候也销毁P就好了,但是V这么多,都得去写P吗?这就需要去封装一个BaseP了

图片描述

可以看到,我在这里定义了一个P的基类软引用来处理V,然后需要我们的MainPresent继承它

图片描述

这些没什么问题,关键还是在BaseActivity中的思路

图片描述

可以看到这边抽取之后可以得到一个Present的对象,并且通过createPresenter让外部可以实现,其他的则绑定了他的生命周期,这样就很好的避免了内存的问题了。

而在Activity中我只要继承了BaseActivity即可

图片描述

可以看到,现在我依旧可以通过BaseP中的mPresenter对象来进行loadData。

到此,MVP就讲解完了,实际上,从始至终,我都是想让你摆脱代码的束缚,掌握这种思想,代码只是一个实现过程。

源码及PPT:

密码:gfk9

点击查看更多内容
27人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
471
获赞与收藏
528

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消