Android 项目重构之路:架构篇

    |     2016年2月22日   |   Android经验   |     0 条评论   |    1743

接手一个按功能切得过细的 Android 项目:17 个模块、好多模块只有两三个类,应用本身最多五个模块就够。模块边界模糊,类职责不清,找 Activity 经常只能翻 Manifest。代码又乱又臭,改一个 bug 冒出另一个,没法做新功能,更满足不了多客户定制。于是重构:搭一个易维护、易扩展、可定制的四层结构。

四层:模型层、接口层、核心层、界面层。模型定义数据;接口封装服务端 API;核心处理业务;界面只负责展示。关系如下:


一、接口层

封装网络底层 API,供核心层调用。起步只留 4 个核心类:

  • PostEngine:请求引擎,发送请求并处理响应
  • Response:封装 Http 返回结构
  • Api:定义全部接口方法
  • ApiImpl:实现全部接口方法

PostEngine 把请求发出去,把返回 json 转成 Response。json 结构固定三类:

{"event": "0", "msg": "success"}
{"event": "0", "msg": "success", "obj":{...}}
{"event": "0", "msg": "success", "objList":[{...}, {...}], "currentPage": 1, "pageSize": 20, "maxCount": 2, "maxPage": 1}

event 是返回码,0 成功;msg 是信息;obj 单个对象;objList 数组;currentPage / pageSize / maxCount / maxPage 分页。Response 基本定义:

public class Response<T> {
    private String event;
    private String msg;
    private T obj;
    private T objList;
    private int currentPage;
    private int pageSize;
    private int maxCount;
    private int maxPage;

    //getter和setter方法
    ...
}

属性名必须和 json 字段一致,否则转不出来。obj / objList 用泛型对应具体类型。Api 方法类似:

public Response<Void> login(String loginName, String password);
public Response<VersionInfo> getLastVersion();
public Response<List<Coupon>> listNewCoupon(int currentPage, int pageSize);

ApiImpl 把参数和返回类型备好,交给 PostEngine:

@Override
public Response<Void> login(String loginName, String password) {
    try {
        String method = Api.LOGIN;
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("loginName", loginName));
        params.add(new BasicNameValuePair("password", EncryptUtil.makeMD5(password)));
        TypeToken<Response<Void>> typeToken = new TypeToken<Response<Void>>(){};
        return postEngine.specialHandle(method, params, typeToken);
    } catch (Exception e) {
        //异常处理
    }
}

二、核心层

夹在接口层和界面层之间,集中做数据处理。向上给界面 Action;向下调接口层请求服务器。Action 类似:

public void getCustomer(String loginName, CallbackListener<Customer> callbackListener);

因为要请求网络,加了 callback。CallbackListener 只有成功/失败:

public interface CallbackListener<T> {
    /**
     * 请求的响应结果为成功时调用
     * @param data  返回的数据
     */
    public void onSuccess(T data);

    /**
     * 请求的响应结果为失败时调用
     * @param errorEvent 错误码
     * @param message    错误信息
     */
    public void onFailure(String errorEvent, String message);
}

实现基本两步:

  • 参数检查:非空、边界、有效性
  • 异步任务调接口层 Api,把结果回调回去

Action 面向界面:同一屏数据可能要调不同 Api。后续可在这里加缓存,但变化太快的数据不适合缓存。


三、界面层

最上层,只负责展示。公司要给不同商户定制不同 app,Android Studio 的 productFlavors 能少很多重复劳动。包不再按功能模块切,而按类型切:

activity、adapter、fragment 各自有基类,抽共用常量、对象和方法。界面层最容易乱、最容易出问题,架构和规范都要先定好。后续文章再展开。


四、模型层

横跨各层,封装数据实体,基本和 json 的 obj 一致。接口层把 obj 转成实体,再经 Action 到界面。还定义常量:用户状态、支付状态等。Api 用 1、2、3,这里改成枚举,免去边界检查,也更好记。枚举必须能把 1、2、3 转回来,两种做法:

1. gson @SerializedName

public enum BooleanType {
    @SerializedName("0")
    FALSE,
    @SerializedName("1")
    TRUE
}

2. 自带 value

public enum BooleanType {
    FALSE("0"),
    TRUE("1");

    private String value;

    BooleanType(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

gson 方式直接访问 TRUE/FALSE 就会序列化成 1/0;第二种没有序列化,要用 getValue。

层级 职责 关键类型
接口层 网络 API、json → Response PostEngine / Response / Api / ApiImpl
核心层 业务与数据处理、回调界面 Action / CallbackListener
界面层 展示、多 flavor 定制 activity / adapter / fragment 基类
模型层 实体与状态枚举,贯穿各层 与 json obj 对应的 model

五、结束

以上是最基本的架构,只列了核心,扩展是下一步。原文出处: Keegan小钢

一句话总结:模块切太碎就按四层重切:接口吃网络、核心吃业务、界面只展示、模型贯穿并用枚举代替魔法数字。

转载请注明来源:Android 项目重构之路:架构篇
本文链接地址:https://ai.zhousir.top/?p=1312
回复 取消