【.com原创】苏宁+App是苏宁易购集团零售云研发中心的主打产品之一。由于项目处于早期阶段,业务逻辑复杂,业务需求变化很快,经常出现在开发甚至测试过程中。界面或后台界面调整。App客户端如何在外部需求不断变化的情况下,降低模块耦合,尽量减少每次代码修改量,一方面减轻开发人员的工作量,另一方面减轻测试工程师的工作量,以及最终顺利完成项目迭代开发。为什么要使用MVP模式相信在2014年之前,大部分人开发Android应用都是使用MVC模式。M和V一般没有问题,Controller层就是对应的Activity类。它的主要职责是加载应用程序的布局和初始化用户界面,接受和处理用户的操作请求,然后做出响应。随着界面及其逻辑的复杂度不断增加,Activity类的职责不断增加,使其变得庞大而臃肿。打开之前项目的Activity时,2000行以上的Activity不在少数。另外,由于项目的特殊性,互联网产品讲究速度,尤其是新产品,上线的时间将决定你的市场占有率。APP的理想情况是UED有可视化草稿,后台界面已经准备好,客户端同学边制作页面边调试界面,自测后测试成功交付。然而,理想很丰满,现实很骨感。现实情况是,我们刚开始Coding的时候,只有一个界面文档和交互图。我们需要思考的是,一定要将接口和接口数据解耦。接口的联调和测试不能依赖于接口的完成。业务层代码完成后,就可以测试业务功能了。基于以上背景,我们选择了MVP模式。什么是MVP模式?我们上面提到的MVP架构是Google开源的一种设计模式。主要是将视图(View)和模型(Model)的功能进行细分,让View只能做两件事:完成用户交互。显示界面布局,让Model做数据处理,业务逻辑放到另一个类(Presenter)中。下面具体分析:M为M层,负责项目中的数据处理,包括本地数据库查询,网络数据的获取都在这一层完成。View是V层。在项目中,就是UI模块,即各种activity/fragments,负责绘制UI元素,与用户进行交互。P即P层,在项目中用作View和Model之间的桥梁。M层和V层不直接交互。M层获取数据后传递给P,P层通过接口回调给View层。同理,View层的事件,比如点击等,都是通过P层通知给M层处理的。如下图所示:MVP模式应用实战苏宁+App项目结构苏宁+App项目结构图如下:当前App整体项目结构如图所示,各层级介绍如下:前端界面层:界面相关的布局,比如各种activity/fragment类。业务逻辑层:与业务逻辑相关,比如各种Presenter类。数据层:数据相关,包括数据的存储和获取,比如各种Model类。运行服务层:随着应用的生命周期自动初始化和销毁??,提供一系列的服务供其他业务模块调用,比如各种Service类。业务框架层:用于当前App与业务之间耦合的公共方法和组件。基础框架层:与业务无关的底层组件,可供多个应用同时使用。系统层:Android系统的底层。从上面的架构图可以直观的看出,我们在日常业务功能迭代的时候,主要修改或者增加的代码都在前三层。这里主要说一下前三层的使用规范。目录结构下图为使用MVP模式时购物车订单确认页面的目录结构:模型—数据处理。presenter——业务处理。任务-网络请求。ui—页面。util-当前模块的公共类。view——页面刷新回调接口。整体逻辑设计如下图所示,是购物车2界面。下面将围绕这个接口来讲解如何使用MVP来实现具体的业务功能。为了更直观的看到MVP在当前业务中的使用,我们画了一张类图和一张时序图。通过类图,我们可以清楚的了解到类的设计,如下图:通过下面的时序图,我们可以清楚的看出调用关系:通过上面两张图,我们可以看出MVP对应的作用和调用关系在当前的业务中。下面继续在代码层面深入讲解。代码实现M层(模型)项目中很多网络请求都是重复的。比如很多页面都会用到店铺信息界面。如果每个页面都要写在不同的Model中,复用性很弱。所以与谷歌在Github上发布的MVPDemo不同,我们项目中的每个网络接口都写成一个单独的任务,以订单确认页面为例:Model层定义了模型抽象类(PSCShopCart2DataSource)。然后调用具体实现类(PSCShopCart2Repository)中的Task发送网络请求。代码如下:IViewMVP模式下,M层和V层不能直接通信,通过Presenter层的接口将数据回调给V层。一般来说,IView中的接口对应V层的功能。这里有人认为特别复杂的场景会出现很多接口。当然,如果出现这种情况,该合并的接口还是应该合并,也可以在Activity中做简单的处理。在实际开发中,一定不要受到框架的限制,不管是什么模式,都是为了业务的正常迭代。代码如下:将原本混在activity/fragment中的P层(presenter)的业务逻辑移到了Presenter中,Presenter作为M和V交互的桥梁。由于Activity和Fragment的生命周期Fragment不同,会影响一些弹框关闭的时机,所以在项目中,Activity和Fragment分别定义了一套基本的业务抽象类。这里使用Activity这个基础业务抽象类来进行演示。Activity中使用的所有Presenter都继承PSCBaseActivityPresenter:PSCActivityNetTask主要监听网络任务并回调Presenter,同时设置生命周期监听器显示加载框。Presenter收到网络回调后,根据接口返回的数据进行业务处理,成功或失败分别通过接口回调到View层,并刷新接口。V层(view)认为大部分app都会有baseActivity作为基类,提取Activity的公共部分进行封装。苏宁的基类叫做SuningActivity/SuningFragment。每个界面都需要绑定/解绑View和Presenter,这些都可以放在基类中。然后定义protectedabstractTcreatePresenter();创建Presenter的步骤交给子类去实现。代码量比较大,这里删掉了,只保留MVP相关的代码,如下:Activity实现上面定义的IView接收数据,同时在当前类中创建Presenter,并通过Presenter方法ask调用Model中的网络。总结以上内容就是我们对MVP架构的理解,待苏宁+项目实战后与大家分享。MVC、MVP、MVVM不分模式都能实现功能。在选择对应的模式时,要看哪种模式能够封装相对于当前业务的变化,从而使各个模块解耦,实现独立的变化,降低未来的成本。维护工作和隐患。当然,我们也不能落入模式的陷阱,用模式来使用模式。没有好的框架,只有合适的框架。如果大家发现我们目前项目中对MVP的使用有不正确或者不完善的地方,欢迎提出来,让我们一起讨论。曹银飞,苏宁云商IT总部Android技术专家,拥有多年Android研发和管理经验。曾就职于联创、腾讯等大型互联网公司,现负责苏宁易购安卓开发部产品开发和技术管理工作。多年Android项目架构设计、性能优化、团队管理实践经验。现在他致力于打造苏宁智慧零售相关的APP,希望能将苏宁的零售科技能力发挥到极致。【原创稿件,合作网站转载请注明原作者和出处为.com】
