APP架子迁移

在完成上一篇之后,断断续续的开始重构我的Android项目代码,现在终于完成了。在重构期间又仔细阅读了一些开源项目的源码及文章,并询问了一些大神思路,按照理解自己完成了MVP结构的重构,与google samples项目的大致一致,但没有完全照搬。本文侧重一些重构过程中思考的问题,,具体的代码可以在Github查看,本文的源码为branch1.1,重构前的是master,最好对比看看重构的区别。

对多重callback逻辑的思考

大量的文章都只介绍读取一次网络然后用一个监听接口处理访问状态,这种是最常见的网络访问规则,如下图所示:

用监听的方式获取访问结果

但实际生产环境哪里仅仅是简单的为列表获取数据而已,要是完成业务逻辑需要多次网络访问呢?来看一次登录过程,我将每一个步骤都截图如下:

基于UMENG SDK访问微信获取token,成功则执行下一步

1.基于UMENG SDK访问微信获取token,成功执行下一步。

基于UMENG SDK获取用户资料(头像、昵称),成功则执行下一步

2.基于UMENG SDK获取用户资料(头像、昵称),成功则执行下一步。

将数据发送服务器进行登录验证

3.将数据发送服务器进行登录验证,完成登录业务。

说起来逻辑很简单,但是从代码实现角度就不够优雅了。在OnSuccess中执行下一步动作,如果不写在另一个方法函数中的话,那么看起来就是一层套一层的结构,可读性很差,我考虑的有几种技巧来尽量提高可读性:

1.添加充足的注释
2.用Handler(之前我是这么做的)
3.用EventBus
4.用RxJava

在这次重构中,我放弃了Handler的方式,如果注释充足,Handler其实并没有提高可读性,而且从MVP架构的角度来思考,之前Handler的编写并没有将View逻辑与Presenter的逻辑分离,全部放在了Handler中,应该尽量避免。

放弃handler了

EventBus在重构中也未使用,因为EventBus的订阅模式更适合一个操作需要通知多个处理的情况(比如收到新消息),否则与监听接口相比阅读性。并未提升太大。

我倾向使用RxJava,虽然准备在下一次重构中才使用,但已经阅读了不少的文章。在注释充足的情况下,现在callback套callback的方式已经能够阅读,但不可忽略的线程安全和内存溢出问题,可以利用RxJava很好的解决(这也是放弃handler的一个原因,你真以为实际生产中new一个出来就可以不管了么..)感兴趣的朋友可以等我的下一个branch,我会来说说我的感受。

MVP重构要一贯坚持到底么?

在google sample的todo例子中,要想从列表页打开新建页,需要点击浮动按钮,这样一个简单的在onClick中搞定的事情,被拆分为三部分,我认为实际有点过了。看看下面的代码:

菜单栏按钮点击事件

如果点击消息列表的按钮,需要首先清除通知badage,然后清除Preference的未读数量,然后进行页面跳转。按照MVP架构思路,清除通知badage应该在View中实现(也就是在Activity里多一个方法);清除未读数量应该在Model的Local中(也就是专门负责本地数据操作的类);跳转应该在View中实现(Activity里面还要多写一个方法)。

那么其实在OnClick中3行代码搞定的时候,你要额外多谢那么多支撑框架的代码,有必要么?再看看Model层的一个例子:

在google sample的todo例子中,网络访问与本地访问分离,一条数据是从本地读取还是从网络读取的逻辑判断,是写在Repository中的。如此毫无问题,思路非常清晰。但如果不存在本地化的需要,可以把代码直接写在Repository中么?(其实可以吧...反正也不影响阅读)

重构之后层次很干净

todo例子中,网络与本地的操作是保持一致的(基础的增删改查),用接口来定义了方法。在实际生产中(比如登录过程),本地与网络的操作差别比较大,因此应该根据实际判断到底是否需要用接口定义方法。

todo例子中,用到了很多Ioc的思想,如果你不用DI库如dagger2或者要做单元测试,可以考虑简化一下,正如我实例化Presenter的代码一样。

重构之后,数据的成员变量该放哪去了?

详情页,需要一个描述商品数据的成员变量;其他用户的介绍页,需要一个描述用户资料数据的成员变量;列表,需要一个数组来保存数据,一个int来保存现在是第几页了。那么MVP结构重构之后,这些变量是不应该仍然定义在Activity中的,那么这些数据应该放在MVP的那一层呢?

安装todo例子中的介绍,包含2方面的重构。首先,数据变量应该写在P层中;其次,对ListView这种包含adapter的控件,数组操作应该写到Adapter中。

Presenter的构造器

以我一个Presenter为例,由于不考虑注入,因此Repository就直接在构造器中自己实例化了。当前列表为第几页的mPage变量,是放在Presenter中了的,每次获取数据后都直接将数据传入View中,再在View中调用Adapter的自定义方法来更新列表(详情见代码)。

ListView的数据操作都在Adapter中定义

在Adapter中,自定义了remove、replace、addAll、getItem等几种常用的数据操作函数,不够再加就是了。自定义这些方法的时候,尤其要注意你是否自己实现了header-view的功能,如果实现了,那么就要计算一下实际的位置(其实特简单,一句话的事)。

后话

其实本来想按照重构后MVP长什么样的思路来写这文章,但是在重构的过程中不断的阅读todo例子的代码,觉得把握住几个关键点,重构的思路就会非常清晰:

1.各种数据操作都要放到M层中去;
2.V层中只需要定义方法的时候把数据设为参数,不管数据从哪来,到哪去;
3.P层负责告诉M层要读哪些数据(get)或者要向服务器发送什么数据(set),根据数据访问情况(成功或失败),将数据传给V层;

这一篇更多的是想把自己重构过程中的一些思考记下来和大家一起讨论,本篇不是这次重构的终点,下一篇我会继续聊如何从这一步继续跨到RxJava函数式编程的范围去。每一次重构是怎么变化的,代码也给了,思路也给了,项目也是应用商店上线的产品(虽然没有钱推广用的人不多),这个系列应该比其他文章的玩具代码参考价值更高吧。如有感兴趣的大神指点一二,或者也在前行的朋友一起来讨论下,那我也觉得深夜码字没有白费了。

APP迁移的更多相关文章

  1. iOS App迁移(App Transfer)注意点

    1.App迁移需要苹果审核吗? 答:不需要 2.App迁移需要多长时间? 答:迁移操作过程很快,A账号发出申请,B账号接收,几分钟时间.App Store 展示B账号相关信息可能几分钟,也可能有延迟几 ...

  2. django 数据库配置 ,APP 迁移.模型基础

    # 1.数据库的连接配置django 连接mysql的配置流程:- 安装 pymysql pip install pymysql- 创建数据库用户有创建数据库权限的用户- 创建数据库crm .进入数据 ...

  3. 如何将App从一个账号迁移到另一个账号?

    App迁移(App transfer):将App从一个开发者账号迁移至另一个开发者账号.此文演示了整个迁移过程,为了方便解释,在此过程中,将App转出的开发者账号我们下文将会称之为A账号,接收杭州Ap ...

  4. 将 Objective-C 代码迁移到 Swift(Swift 2.0更新)-b

    本节内容包括: 为你的Objective-c代码做好迁移准备 (Preparing Your Objective-C Code for Migration) 迁移过程(The Migration Pr ...

  5. 哪些产品不用开发原生APP,微信公众号就够了?

    最近一阶段H5技术被推到高峰,很多人认为借助H5就能利用微信公众号取代APP原生应用了,而事实是怎么样的?这里我从产品层做一个客观分析. 一,原生APP总体趋势 要谈APP是否会被微信取代,那么必须回 ...

  6. 个人作业2:APP案例分析

    产品 产品名 网易云音乐 选择原因 除社交软件和浏览器以外,在手机里存在最久的也是使用次数最多的APP就是它了.不管换多少次手机和电脑,它始终在我的装机必备名单上. 调研与评测 第一次上手体验 第一次 ...

  7. Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第二部分(Page 7)

    编写你的第一个 Django app,第二部分(Page 7)转载请注明链接地址 本教程上接前面的教程.我们会配置数据,创建你的第一个 model,并对Django 自动生成的 admin 站点进行快 ...

  8. 视图控制器的View整体上移问题

    最近我朋友代码出现一个问题,我看了下,发现已经是适配iOS那时候的问题了 如果你准备将你的老的 iOS 6 app 迁移到 iOS 7 上,那么你必须注意了.当你的老的 app 在 iOS 7 设备上 ...

  9. iOS 与 惯性滚动

    注:以下所有例子均 只 在 iOS 的微信中测试过,但对于饿了么APP的内置浏览器同样适用(两者使用相同内核) 引题 工作中常常有需要显示大量信息的情况,列表超出一屏就涉及到滚动的问题.例如 - va ...

随机推荐

  1. 语句分类及if语句

    一.语句分类: 1.顺序语句2.分支语句 if语句.switch语句 3.循环语句 (1)初始条件 (2)循环条件 (3)循环体 (4)状态改变 二.if语句: 1.if语句4中情况: if(条件){ ...

  2. 使用Groovy进行依赖注入

    为什么选择Groovy? 传统的依赖注入是XML,对我而言,可读性太差,太不美观,强烈地想换一个方式进行依赖注入,Groovy作为XML的替代方案,在Spring4之后被引入,是基于JVM的一门方言, ...

  3. 如何查看程序被哪个版本编译器编译的linux-gcc

    如何查看程序被哪个版本编译器编译的linux-gcc http://bbs.csdn.net/topics/380000949 那是不可能的,除非你加入了调试信息,也就是编译的时候加入了-g参数,然后 ...

  4. BZOJ 1600: [Usaco2008 Oct]建造栅栏( dp )

    QAQ我没读过书...四边形都不会判定了 简单的dp.... --------------------------------------------------------------------- ...

  5. 一种解决h5页面背景音乐不能自动播放的方案

    场景:微信.浏览器.App 普通解决方案:采用audio标签的autoplay属性 现象: 大部分IOS系统和少部分Android微信不支持自动播放 $解决方案:监听WeixinJSBridgeRea ...

  6. HTML5 总结-服务器发送事件-9

    HTML 5 服务器发送事件 HTML5 服务器发送事件(server-sent event)允许网页获得来自服务器的更新. Server-Sent 事件 - 单向消息传递 Server-Sent 事 ...

  7. 微信开放平台 获取 component_verify_ticket

    <?php /** * @author zhaozhuobin * @date:2016-06=07 * */ namespace common\components;use DOMDocume ...

  8. python中os.walk浏览目录和文件

    #!/usr/bin/env python # 2.py # use UTF-8 # Python 3.3.0 # os.walk()的使用 import os # 枚举dirPath目录下的所有文件 ...

  9. ubuntu ~/.bash_history

    sudo apt-get update sudo apt-get install python-pip sudo pip install Django==1.7.1 sudo apt-get inst ...

  10. IE 兼容性问题

    1.IE6-IE7 可能会有2个class属性,真TMD蛋疼,一个是初始的,后来的是js赋值的 2.不同浏览器的标签默认的margin和padding不同 解决方法: * { margin:0; pa ...