接上一篇,这一篇开始用android来解释MVP概念、八股式的架子结构和命名规范。我在准备这篇文章的时候还看到不少在MVP基础上衍生的架子思路,底子是MVP没错,但命名有区别、复杂度变了、架子也用到了module拆分而不单纯用包进行拆分,所以接下来会基于googlesamples推荐的命名、架子结构来重构我的约炮APP,我会pull个新的branch来对应各个章节,接下来会从我认为合适的难度适中、实用的方向继续重构。

搭架子切忌过度!。搭架子就是为了隔离代码,该干嘛干嘛(说白了就是就是读数据的放一个文件夹,界面放一个文件夹)。现在流行的“domain”、“repository”、“Service”等命名,你若.net出家肯定会心一笑:“又TM来装逼了”--这些命名和早年的"module"、“Biz”、“helper”命名如出一辙(你可以去苏菲论坛看看大神几年前写的,至今也非常好用的那套.NET通用库)。

当你觉得看不明白的时候就该收手了。还是再强调一次这种观点,比如我为了准备文章看了这篇clean-architecture和这篇mosby。一脸的懵逼,并不是因为鸟语差,我可以毫不费劲的看完,而是因为我在看的时候脑海里一直深深的感觉“我有必要这样搞么?”,后面我突然明白,广点通2毛钱收入不是因为架子差,而是因为crash太多,哈哈哈。看不明白了还要继续装逼,就像刚开炉罩就寻思怎么承载千万级并发一样傻逼。你只要记住哪个文件夹放什么代码文件,干些啥这种层度,就足够受用了。

顺便预告一下,在后面讲IOS端,我会来讲讲MVC模式怎么结合搭架子的思路,正好也为出文章给点动力马拉松一次把一直想做的ios端做了(因为到现在用广点通收入才2毛钱不想弄,哈哈哈)。IOS现在炒MVVM火的很,关于MVVM模式我是很拒绝的,在早年做silverlight的时候用过,觉得太麻烦了(这也是我想提的观点,不要过度),数据绑定这件事,逻辑简单还好,要做很多其他工作,你光是写架子的基础代码就够折腾了。在后面讲PHP端(Laravel)的时候,我就聊聊文件夹该怎么放,文件名该怎么取显得很专业,以伟大又优雅的laravel框架来总结下全篇。

值得看的文章和项目

自从微博关注了很多大神和几个开发博客之后,各种技术文章炸屏有没有..尤其是像我这种好奇心胜的,关注的方向不少,看得很压抑啊。这里我先给几个我认为你应该学习的文章和项目,比我写的好、写的生动(打星标是指我认为的阅读友好度)。

项目,要发现新的会编辑添加:

白话MVP模式

在学习架子的过程中,各种翻译差异和理解误差造成了诸多困扰,什么是“业务逻辑”?“领域层”?“数据映射层”?很烦有没有,尤其是早期网上的文章作者都是大神,觉得人民群众都是学霸,也不给点例子就用无比晦涩的描述带过去了。好在现在很多大神发现了这一点,开始用生动轻巧的语言来描述这些概念。前面推荐的文章相信你也吸收的差不多了,我就结合实际细节再白话一遍MVP模式(我没老司机带,理解偏差请纠错)。

你跟我一样吗

以前你是不是在一个叫data或者bean或者model的包里面放了很多数据实体?如“UserBean”,定义用户的名字、性别字段,添加get/set方法,持久化(Parcelable),用gson或orm的话还会加上@SerializedName、@Table之类的注入。

你定义数据的地方

接下来你会把网络访问哪个网址取得用户数据的代码写在一个叫Manager或者Api或者Network的包里面,json数据从网络读取并通过gson转换你会写在listview所在的fragment或者activity文件中(比如叫loadNewData)。

你定义网络访问的地方

你把网络访问数据转换为listview可读取数据的地方

如果你是有心之人,那么你还会写sqlite操作的逻辑并放在一个叫dao或者db的包,把数据写入到sqlite中去存起来。每次从数据库读或者写,会用asyncTask执行(可能你会新建一个叫task的包或者listview所在的fragment或者activity文件中,当时我图省事没弄)

如果你拿着票子想让功能更健壮,上传数据的代码写在service里面,那就会添加一个service包;需要添加notification,那么你会新建一个叫boardcase的包和notification的包,一个存广播、一个存notificaition;图片处理、时间字符串处理等功能写在一个叫utils的包里面;第三方轮子View控件写在一个叫widget的包里面。

发现啥问题没

写代码讲究个“逻辑分离”,简单讲读写数据的凑一堆;读写网络的凑一堆;界面交互(包括数据显示)凑一堆,这样的好处就是维护起来方便,易于扩展(项目小没这种体验?那在硬盘里面,代码放一个文件夹,ui设计素材放一个文件夹,文档放一个文件夹,要用的时候直接打开哪个文件夹心里了如指掌,这样理解了吧)。

那其他文章里总是提“业务逻辑”、“功能逻辑”,怎么区分呢。以登录功能来举例:

  1. 你用手机号或者微信登录,验证格式或者通过微信获取token和userinfo,都是为了实现登录功能,但是方法不同,完成这些操作你可以调用umeng或者第三方的原生SDK,为这些写代码,算业务逻辑。
  2. 把用户注册信息发送到服务器保存,并接收服务器反馈(比如保持用户登录状态的token),存进preference或者数据库,这些代码算业务逻辑。
  3. 怎么把数据就存入preference或者数据库,无非就是增删改查,那么这部分代码就算功能逻辑。

为实现具体业务功能写的代码,叫做“业务逻辑”。登录的时候获取人员位置、短信验证码都算。并且,你存入数据库之前需要修改服务器反馈的数据(比如从微信拿用户性别是m、f,你想存为0、1表示),这种代码也算入业务逻辑中去的。在各种架子中,“domain”、“service”、“repository”里面干的全是这些事。

为实现可复用的功能函数代码,叫做“功能逻辑”。不管业务是登录还是注销,想访问网络或者读取数据库,最后都会调用平台的方法吧,那么如何调用平台方法的代码,就是功能逻辑。如访问网络,不管是想post登录的网址或者post注销的网址,都会用到调用android网络访问的代码;如增删改查,不管你是preference或者sqlite,最后都会调用android方法执行;如数组转换、临时文件管理、图片压缩、检查字符串是否为空、md5加密、时间格式化等等,你可以写一个叫utils的包保存这些代码。boardcase、receiver、sevice、notifacation都应该以包为单位分离。

很多轮子已经帮你搞定了,比如读取图片的Glide或则网络访问的okhttp

按照这样的思路进行细分,那么很明显的,上一节中目前我app的框架虽然包的结果清晰,但是读起来是一团糟的,而且确实是“读”起来一团糟,比如index的fragment代码行数过高,我不得不简单的把代码“挪”到一个BaseIndexFragment中,简单的把数据读取和界面交互的代码分开便于阅读。MVP模式就很好的解决了我这样不专业的分离方案,提供了标准模板,什么代码该放哪就放哪。

Model层不再只是放数据实体了

按照MVP的说法,Model层是要把所有和数据有关的代码都放在这里的,也就是说定义数据实体、网络读取json并转换为数据数组、数据库读写数据这些代码全部都写在这里。Presenter层想获取数据,那就一定是已经处理好不需要再处理的数据了,怎么获取数据(从网络或者数据库)的、数据怎么转换的,通通都不用管。

数据处理全部移步Model层

在项目里面体现在什么地方呢,listview所在的fragment中,从网络获取json并转换为数据数组操作的代码从原来的loadNewData函数中移到了Model层的XXRemoteDataSource文件中去。从数据库获取数据的asyncTask代码移到了XXXLocalDatasource中去,判断显示本地数据还是网络数据的代码移到了XXXDataRepository中去。这样一来,fragment中的代码一下就清爽了很多,是不是感觉很好?我们继续看Presenter。

Presenter层就像电梯

数据读取前、读取后该干嘛?点击登录按钮后服务器返回登录状态该跳转首页还是提示密码错误?这些事都是Presenter干的:把Model层准备好的数据显示在界面上,有交互时提醒Model层数据需要更新。就像一台电梯,人进来,去按摩到3楼,去ktv到4楼,去开房到5楼。进来的是男是女你不需要关心,出去干嘛你也不需要关心。

在Presenter层里面会大量用到接口(interface)定义行为。以前是不用接口的,第一嫌麻烦,第二人家是团队这样方便测试,我只搞暴力测试没那么讲究。现在还是老老实实用吧,如果不习惯你可以先实现功能,再重构接口,或者把常用的增删改查先复制进去用,慢慢习惯。

要开始写接口了,有点心理准备

这时你可能会有一定的困惑,如果有涉及诸如IM通信、百度LBS定位这样功能逻辑的代码,该放哪里?这些代码可能需要依赖上下文(就是构造函数要context或者activity,你肯定见过),我认为应该放到utils包里面。传递参数、状态成功或失败该怎么处理的代码才放到Presenter中去。也就是说和界面有关的代码才放在Presenter中,其他按业务逻辑或功能逻辑能归类的尽量重构。

View层不是指的控件

这里的View是思想,不是具体指按钮控件或者列表。你可以脑补一个画面:View和Presenter在床(fragment或activity)上搞基,一会Viwe在上面,一会Presenter在上面。

View是让你在通知界面哪个该隐藏了,哪个该刷新了

从一个简单的新闻列表,到复杂点有轮播banner、多级下拉菜单,都可以在View层中表达控件的状态和交互动作,通知presenter这个控件被点击要执行啥操作了,或者prenseter通知这个控件应该被隐藏或显示了。View层在MVP结构中,反而是写代码量较轻的一块,只要Model和Presenter写好了,明天在github上看到一个更酷炫的轮子或者想添加一个动画效果,都是很清爽的事。

聊聊别的

我相信你已经看过我推荐的那几篇文章了,那么我这很白话的把mvp模式讲了一遍,用很多平时会用上的细节来解释,应该对概念的把握比较深刻了。那么在我把我的项目更新完成写下一篇之前,我们再聊聊别的。

RxJava和handler到底该用哪一个?

你们是不是也喜欢把自定义的handler写在fragment文件里面?或者asyncTask之类的,或者adapter。功能简单点的倒是问题不大,这样写又快又省事,阅读性也可以。但要是你遇上登录功能,首先通过umeng获取用户信息,成功了再从服务器获取七牛的上传token,然后传图片,图片上传成功把头像地址和用户信息post到数据库里面,成功了从服务器获取token存app数据库。像这样“圆环套圆环”的业务代码,画时序图都挺麻烦,用handler可以写,但是隔一段时间再阅读起来就很不开心了。

频繁的网络访问会让handler变得臃肿

RxJava的流编程思路就可以很好的解决这种问题,虽然代码量并不见得变少,但却是可以让阅读起来开心一点。至于网络模块你用async-http-client或者okhttp或者volley,或者最近很火的retrofit2,这就看自己了吧。我一直在用async-http-client,够老的轮子了吧,也没觉得有什么不妥的(可能我的网络访问规则太简单了)。另外你想当技术网红的话,RxJava+Retrofit2是必备神器,但要.net出家的人,还是呵呵吧,没必要炒到这种高度。

我的文章肯定有问题,求指正

我没老司机带,全靠github和逆向工程学习。肯定会有问题,还请发现了指正,非常感谢!qq群533838427

APP架子迁移指南(二)的更多相关文章

  1. APP架子迁移指南(一)

    搭架子是脑垂体在放烟花 俗话说吃多少饭,走多少路,上学的时候捧着<设计模式>就想睡觉,现在轮子看得多了,自然有心领神会之感.搭架子就像谈哲学,如高山流水,遇弯则急.遇潭则深.我印象最深的是 ...

  2. APP架子迁移指南(三)

    在完成上一篇之后,断断续续的开始重构我的Android项目代码,现在终于完成了.在重构期间又仔细阅读了一些开源项目的源码及文章,并询问了一些大神思路,按照理解自己完成了MVP结构的重构,与google ...

  3. App架构师实践指南二之App开发工具

    App架构师实践指南二之App开发工具     1.Android Studio 2.编译调试---条件断点.右键单击断点,在弹出的窗口中输入Condition条件.---日志断点.右键单击断点,在弹 ...

  4. Spring Cloud Alibaba迁移指南(二):零代码替换 Eureka

    自 Spring Cloud 官方宣布 Spring Cloud Netflix 进入维护状态后,我们开始制作<Spring Cloud Alibaba迁移指南>系列文章,向开发者提供更多 ...

  5. Magento网站迁移指南

    "Magento网站迁移指南":关键词:magento 网站 迁移 指南 上周五,为mkt同事迁移了一个从本机到godaddy的magento系统. 中间出了不少状况, 现在写个迁 ...

  6. App Store生存指南

    资格获取   如果已经有App Store开发帐号请跳过此节.   App Store的资格获取其实一直以来都不算难,和其它事情一样,需要的只是耐心.现在苹果对申请者的文书手续要求已经比几年前简化多了 ...

  7. 精华阅读第 12 期 | 最新 App Store 审核指南与10大被拒理由?

    很多时候,我们对技术的追求是没有止境的,我们需要不断的学习,进步,再学习,再进步!本文系移动精英开发俱乐部的第12期文章推荐阅读整理,其中涉及到了 Android 数据库框架,架构设计中的循环引用,同 ...

  8. DCloud-HTML5+:5+ App开发入门指南

    ylbtech-DCloud-HTML5+:5+ App开发入门指南 1.返回顶部 1. 5+ App开发入门指南 App App入门 HTML5 Plus应用概述 HTML5 Plus移动App,简 ...

  9. 【转】总结:2015这一年App Store审核指南都有哪些变化

    本文针对此前版本的<App Store审核指南>进行了更新,并标注了2015年苹果对<App Store审核指南>进行的一些调整. App Store Review Guide ...

随机推荐

  1. WebApi深入学习--概述+路由查找

    如何创建Controller这里就不说了,只写一些可能是高阶知识的内容 关于WebApi的官方介绍及示例 http://www.asp.net/web-api/ 1.跨域 Asp.NET有专门的跨域扩 ...

  2. 【函数】Oracle函数系列(2)--数学函数及日期函数

    [函数]Oracle函数系列(2)--数学函数及日期函数 1  BLOG文档结构图 2  前言部分 2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不 ...

  3. 【转】RHadoop实践系列之二:RHadoop安装与使用

    RHadoop实践系列之二:RHadoop安装与使用 RHadoop实践系列文章,包含了R语言与Hadoop结合进行海量数据分析.Hadoop主要用来存储海量数据,R语言完成MapReduce 算法, ...

  4. 大型网站的 HTTPS 实践(1):HTTPS 协议和原理

    转自:http://op.baidu.com/2015/04/https-s01a01/ 1 前言 百度已经于近日上线了全站 HTTPS 的安全搜索,默认会将 HTTP 请求跳转成 HTTPS.本文重 ...

  5. MySQL运行状态show status中文详解(转)

    要查看MySQL运行状态,要优化MySQL运行效率都少不了要运行show status查看各种状态,下面是参考官方文档及网上资料整理出来的中文详细解释: 状态名 作用域 详细解释 Aborted_cl ...

  6. Java api 入门教程 之 JAVA的IO处理

    IO是输入和输出的简称,在实际的使用时,输入和输出是有方向的.就像现实中两个人之间借钱一样,例如A借钱给B,相对于A来说是借出,而相对于B来说则是借入.所以在程序中提到输入和输出时,也需要区分清楚是相 ...

  7. Java的String.valueOf 转换 与、空串+类型变量转换与封装类(Integer)的toString方式转换比较。

    1.空串+类型变量方式转换 int i=20; String s=""+i; 这种方式实际上经过了两个步骤,首先进行了i.ToString()把 i 转换为 字符串,然后再进行加法 ...

  8. Linux学习--------一

    用户不能直接操作Kemel,所以需要通过Shell来操作Kemel(内核) Shell 分为CLI与GUI两种 CLI:Command Line Interface GUI:Graphical Use ...

  9. shell脚本实现随机筛选

    #!/bin/bash name=(val1 val2 val3 val4 ...) a=$() #以时间产生随机数向39取余得到0~38的值

  10. WinCE下GPRS自动拨号软件(GPRS AutoDial)

    之前在WinCE下调试USB的3G Modem时,写过一个拨号助手RASManager,基本能用.后来车机卖到俄罗斯去,客户老M提供了一个更好的GPRS自动拨号软件GPRS AutoDial,功能完善 ...