Android MVP框架学习实践
前言
想着互联网公司都基本都有现成的项目,实习的话最多也就是对原有的代码修改,增加功能。所以最后进了一家不大不小的外包公司,想体验一下一个商业项目从落地到成型的过程。进入公司以后,被分配到一个给国外发包方做的项目(我只是个实习生萌新啊,第一个项目就给外国人做,这样好吗喂)。
作为一个有过Android开发经验的菜鸟,也算在各个服务外包比赛中拿过些奖的人(虽然大学的这种比赛很水,但是也是有些开发的工作量的,哈哈),我对一个项目的构成,如何开发等等,都有些了解。由于之前的比赛项目经验,都是我一个人独立开发Android端,所以对项目的架构、框架等都是怎么方便怎么来,不怎么考虑代码的可读性,可复用性之类的东西(进入公司实习之后才发现,这些东西相当重要啊),之前为了方便,把业务逻辑,视图绑定啥的都一股脑的放入activity类中,导致activity类过于臃肿,给代码的阅读和修改都带了极大的不便,但是由于自己的项目经验缺乏,从一开始就给自己挖下的坑,之后不但很难填,而且还越挖越深(单手捂眼笑哭.jpg),幸好只是我一个人自己开发,不然要是协作开发的话,估计会被小伙伴怒锤。
进入公司以后,从Android带队开发大佬那边拿到了项目的基础开发框架
品了一下,从我裸考过六级的水平来看,嗯,这个presenter应该是之前在书上看到过的MVP中的P没差了。从网上找找资料学习学习。
进入正题。
MVP是Model、View、Presenter的缩写。Model表示模型,主要负责数据的加载;VIew表示视图主要负责视图绑定,界面的展示,界面逻辑跳转等;Presenter是表示器,主要作为View和Model的中间人,完成他们之间的交互,从而实现高内聚低耦合的思想。画了一幅它们之间的关系图。
可能这样有点抽象,talk is cheap, show you the code.
先来看看我们项目组Android大佬的MVP框架实现,
MainActivity.java:
MainContract.java:
MainPresenter.java:
大佬果然是大佬,已经对各种基类进行了封装,来方便我们这些萌新的开发。(上面的代码还用到了RxJava,emmmm其实这个对于我这个萌新来说也是还没有接触过的技术,之后也会更新RxJava相关的学习博客,要努力变强~)。
我们会发现,其实上面这三个.java已经可以实现一个界面的完整逻辑,但是View有了,Presenter也有了,Model去哪了???还有Contract又是什么鬼???这还是MVP的设计模式吗???
一开始,我也是懵的,又去大佬那边学习了一波。了解到,目前Android的MVP设计模式其实还没有一个统一的标准,基于MVP这个思想可以有很多的实现方式,上面展示的这个方式是Google官方提出的一种MVP实现方式。
谷歌官方的MVP实现方式中,弱化了Model的作用,将Model融入到了Presenter中,我们可以看到MainPresenter中的getBook方法,其实就是Model的实现。而Contract类,中文翻译就是契约类,契约这个词很形象,它作为view和presenter之间的接口,定义了view和presenter上所要实现的方法,然后view和presenter再各自实现其方法,让整个界面的逻辑变得相当清晰。
由于大佬的代码经过了封装,有些细节被隐藏了,所以我们来做个小demo,用谷歌官方的MVP实现方式来实现一个 --模拟从服务器拉取信息展示到界面-- 的程序,更直观的了解MVP。
我的表演
先看一下最后呈献的界面吧
界面布局很简单,就一个TextView和一个Button,布局文件xml就不贴出来了。主要的功能是点一下获取数据的按钮,模拟从服务器获取数据,然后在textview上显示出来。
下面的代码结构,由Activity(也就是View)、Presenter、Contract组成:
为了讲解方便,我们先来看一下MainContract里的内容:
相当简单,因为Contract是一个契约类,里面并没有实现任何功能,只是写明了Presenter和View分别要实现的接口,我在Presenter接口中定义了LoadData的方法,MainPresenter需要实现Presenter接口中的LoadData方法,来完成对数据从服务器的拉取;在接口View中定义了onDataLoaded的方法,同样,因为MainActivity应用了接口View,因此需要对onDataLoaded方法进行实现。
MainActivity:
MainActivity主要是界面组件的绑定,以及一些成员变量的初始化,可以看到我这里初始化了textview、button还有一个presenter,之后界面关于数据的操作就通过presenter来实现。
我们可以看到,这里重写了onDataLoaded的方法,因为MainActivity implements了契约类中的View接口,因此需要将接口中的onDataLoaded方法实现,该方法的主要功能就是将presenter中获取到的数据呈现在界面上,我们这边是将数据显示在界面的textview上。
MainPresenter:
MainPresenter是界面数据操作实现的地方,他implements了契约类的Presenter接口,因此需要实现Presenter接口中定义的LoadData方法,该方法的功能是从服务器获取数据然后回调给Activity(也就是View),我这边偷懒了,没有服务器获取数据,直接hard code出数据(嘻嘻),嗯,假装获取到了服务器端的数据,然后调用View的onDataLoaded方法,将所获取到的数据传递到activity中。这样activity中就可以更新数据了。
奥,对了,Presenter中必须有一个View的成员变量MainContract.View mView; 不然就不能调用view上面的方法了,mView的初始化,在Presenter变量创建的时候复制,可以在MainActivity中看到
看一下运行的结果
由此,我们已经实现了一个相当相当简单的基于MVP框架的app。
如果之后需要加功能,只要在Contract中添加所需要功能的接口,然后再在Presenter和Activity中分别实现就行。
比如说我要新增一functionA,执行完后需要在View上做出相应的界面改变。我们只需要这样做:
1、在Contract中定义Presenter中functionA方法,以及View中的onFunctionAFinished方法
2、在Presenter实现类中实现functionA具体方法,并调用更新界面的onFunctionAFinished
3、在Activity中实现onFunctionAFinished方法
这样,又一个功能被添加了,是不是很方便,逻辑也很清晰。Activity只需负责界面更新的部分,而数据的获取,全都交由Presenter来实现,高内聚低耦合,对于界面的维护和开发相当有帮助。
当然,以上只是MVP一个最简单不过的实现了,为了易于理解,我对很多基类的定义和封装都去掉了,在实际的开发中是不可能那么简单的,但是,如果对于MVP的思想理解了,实现起来还是思路很清晰的。