在完成上一篇之后,断断续续的开始重构我的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. APP架子迁移指南(一)

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

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

    接上一篇,这一篇开始用android来解释MVP概念.八股式的架子结构和命名规范.我在准备这篇文章的时候还看到不少在MVP基础上衍生的架子思路,底子是MVP没错,但命名有区别.复杂度变了.架子也用到了 ...

  3. App架构师实践指南三之基础组件

    App架构师实践指南三之基础组件 1.基础组件库随着时间的增长,代码量的逐渐积累,新旧项目之间有太多可以服用的代码.下面是整理的公共代码库. 2.关于加密密钥的保护以及网络传输安全是移动应用安全最关键 ...

  4. App Store生存指南

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

  5. Magento网站迁移指南

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

  6. Oracle JDK迁移指南

    Oracle JDK迁移指南 https://docs.oracle.com/en/java/javase/11/migrate/index.html#JSMIG-GUID-C25E2B1D-6C24 ...

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

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

  8. 最新App Store审核指南与10大被拒理由

    最近,苹果在官网给出了截至2015年2月份应用被拒绝的十大理由,其中50%以上的应用被拒绝都是因为这10个原因,其中7个理由和2014年相同,其中排名前三的原因分别是:需要补充更多信息.存在明显的bu ...

  9. ASP.NET Core 2.x 到 3.1 迁移指南

    一.前言 今日(2019/12/4).NET Core 3.1 正式发布了,ASP.NET Core 3.1 随之发布,这次 3.0 到 3.1经过了两个月的短周期,并没有增加重大的功能,主要是对 3 ...

随机推荐

  1. 深入解析Windows操作系统笔记——CH1概念和术语

    1.概念和工具 本章主要介绍Windows操作系统的关键概念和术语 1.概念和工具 1.1操作系统版本 1.2基础概念和术语 1.2.1Windows API 1.2.2 服务.函数和例程 1.2.3 ...

  2. 按要求编写Java应用程序。 (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。 创建第

    package com.hanqi.test; public class jidongche { private String chepaihao;//车牌号 private int speed;// ...

  3. 记一次使用openrowset 的坑

    前几天被老大训斥连openrowset 都不会用,然后我就去看了文档,想测试一下栗子~ openrowset 的具体语法我就不贴了,戳这里:https://msdn.microsoft.com/zh- ...

  4. 未进入Kali Linux系统修改修改密码的方法

    今天使用kali的时候,由于虚拟机太多,密码还不一样,就忘记kali的登录密码了(我就是鱼的记忆,只有七秒).... 1.重启kali,进入恢复系统,按e键进入编辑模式 2.光标移动到/boot/vm ...

  5. 在报表中给session赋值实现报表间参数共享

    1. 问题描述 在报表开发工具FineReport中,若有几张不同的报表,每张报表都有一个共同的项可以选择,比如日期时间.我们希望选择了第一张报表的时间之后,其他报表的默认时间都变为第一张报表选择的时 ...

  6. Editor扩展之查看Prefab用在那儿

    Prefab查找需求 在项目开发阶段的中后期,工程中有越来越多的Prefab,当我们要修改一个prefab或删除无用的prefab时,或许我们不是那么清楚该prefab在那些场景中使用着或从未使用过, ...

  7. 在ubunt14.04(linux)下利用cmake编译运行opencv程序

    今天在电脑上安装好了opencv环境,迫不及待的想写个程序来测试一下.但是在windows下我们用vs等集成开发工具.可是在linux下我们应该怎么办呢? 这里我们用了opencv推荐的cmake来编 ...

  8. noip2013 积木大赛

    题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成 ...

  9. JavaScript Date 对象

    JavaScript Date 对象 Date 对象 Date 对象用于处理日期与实际. 创建 Date 对象: new Date(). 以上四种方法同样可以创建 Date 对象: var d = n ...

  10. k-d tree 学习笔记

    以下是一些奇怪的链接有兴趣的可以看看: https://blog.sengxian.com/algorithms/k-dimensional-tree http://zgjkt.blog.uoj.ac ...