Android 项目重构之路:实现篇

转载 2015年11月20日 13:43:47

IDE采用Android Studio,Demo实现的功能为用户注册、登录和展示一个券列表,数据采用我们现有项目的测试数据,接口也是我们项目中的测试接口。

项目搭建

根据架构篇所讲的,将项目分为了四个层级:模型层、接口层、核心层、界面层。四个层级之间的关系如下图所示:

实现上,在Android Studio分为了相应的四个模块(Module):model、api、core、app
model为模型层,api为接口层,core为核心层,app为界面层。
model、api、core这三个模块的类型为library,app模块的类型为application。
四个模块之间的依赖设置为:model没有任何依赖,接口层依赖了模型层,核心层依赖了模型层和接口层,界面层依赖了核心层和模型层。
项目搭建的步骤如下:

  1. 创建新项目,项目名称为KAndroid,包名为com.keegan.kandroid。默认已创建了app模块,查看下app模块下的build.gradle,会看到第一行为:

    这行表明了app模块是application类型的。
  2. 分别新建模块model、api、core,Module Type都选为Android Library,在Add an activity to module页面选择Add No Activity,这三个模块做为库使用,并不需要界面。创建完之后,查看相应模块的build.gradle,会看到第一行为:
  3. 建立模块之间的依赖关系。有两种方法可以设置:
    第一种:通过右键模块,然后Open Module Settings,选择模块的Dependencies,点击左下方的加号,选择Module dependency,最后选择要依赖的模块,下图为api模块添加了model依赖; 

    第二种:直接在模块的build.gradle设置。打开build.gradle,在最后的dependencies一项里面添加新的一行:compile project(‘:ModuleName’),比如app模块添加对model模块和core模块依赖之后的dependencies如下:

    通过上面两种方式的任意一种,创建了模块之间的依赖关系之后,每个模块的build.gradle的dependencies项的结果将会如下:
    model:

    api:

    core:

    app:

创建业务对象模型

业务对象模型统一存放于model模块,是对业务数据的封装,大部分都是从接口传过来的对象,因此,其属性也与接口传回的对象属性相一致。在这个Demo里,只有一个业务对象模型,封装了券的基本信息,以下是该实体类的代码:

接口层的封装

在这个Demo里,提供了4个接口:一个发送验证码的接口、一个注册接口、一个登录接口、一个获取券列表的接口。这4个接口具体如下:

  • 发送验证码接口
    URL:http://uat.b.quancome.com/platform/api
    参数: 

    参数名 描述 类型
    appKey ANDROID_KCOUPON String
    method service.sendSmsCode4Register String
    phoneNum 手机号码 String

    输出样例:

  • 注册接口
    URL:http://uat.b.quancome.com/platform/api
    参数: 

    参数名描述类型
    appKeyANDROID_KCOUPONString
    methodcustomer.registerByPhoneString
    phoneNum手机号码String
    code验证码String
    passwordMD5加密密码String

    输出样例:

  • 登录接口
    URL:http://uat.b.quancome.com/platform/api
    其他参数: 

    参数名 描述 类型
    appKey ANDROID_KCOUPON String
    method customer.loginByApp String
    loginName 登录名(手机号) String
    password MD5加密密码 String
    imei 手机imei串号 String
    loginOS 系统,android为1 int

    输出样例:

  • 券列表
    URL:http://uat.b.quancome.com/platform/api
    其他参数: 

    参数名描述类型
    appKeyANDROID_KCOUPONString
    methodissue.listNewCouponString
    currentPage当前页数int
    pageSize每页显示数量int

    输出样例:

架构篇已经讲过,接口返回的json数据有三种固定结构:

因此可以封装成实体类,代码如下:

上面4个接口,URL和appKey都是一样的,用来区别不同接口的则是method字段,因此,URL和appKey可以统一定义,method则根据不同接口定义不同常量。而除去appKey和method,剩下的参数才是每个接口需要定义的参数。因此,对上面4个接口的定义如下:

Api的实现类则是ApiImpl了,实现类需要封装好请求数据并向服务器发起请求,并将响应结果的数据转为ApiResonse返回。而向服务器发送请求并将响应结果返回的处理则封装到http引擎类去处理。另外,这里引用了gson将json转为对象。ApiImpl的实现代码如下:

而http引擎类的实现如下:

至此,接口层的封装就完成了。接下来再往上看看核心层吧。

核心层的逻辑

核心层处于接口层和界面层之间,向下调用Api,向上提供Action,它的核心任务就是处理复杂的业务逻辑。先看看我对Action的定义:

首先,和Api接口对比就会发现,参数并不一致。登录并没有iemi和loginOS的参数,获取券列表的参数里也少了pageSize。这是因为,这几个参数,跟界面其实并没有直接关系。Action只要定义好跟界面相关的就可以了,其他需要的参数,在具体实现时再去获取。
另外,大部分action的处理都是异步的,因此,添加了回调监听器ActionCallbackListener,回调监听器的泛型则是返回的对象数据类型,例如获取券列表,返回的数据类型就是List,没有对象数据时则为Void。回调监听器只定义了成功和失败的方法,如下:

接下来再看看Action的实现。首先,要获取imei,那就需要传入一个Context;另外,还需要loginOS和pageSize,这定义为常量就可以了;还有,要调用接口层,所以还需要Api实例。而接口的实现分为两步,第一步做参数检查,第二步用异步任务调用Api。具体实现如下: