去年10月底換到了新公司,作移動研發組的負責人,剛開始接手android項目時,發現該項目真的是一團糟。首先是其架構,是按功能模塊進行劃分的,原本按模塊劃分也挺好的,但是,他卻分得太細,總共分爲了17個模塊,而好幾個模塊也就只有兩三個類而已。但應用自己其實比較簡單,要按功能模塊來分的話,最多五個模塊就夠了。另外,有好多模塊劃分也很模糊,也有不少類按其功能其實能夠屬於多個模塊的,也有些類定義不明確,作了不應作的事。有時候,我要找一個界面的Activity,按照其功能應該屬於A模塊的,但是在A模塊裏卻找不到,因而,我只好去AndroidManifest文件裏找了,找到才發現原來在B模塊裏。也有時候,我要找另外一個界面的Activity,可我看遍了全部模塊,也沒看出這個界面應該屬於哪一個模塊,無法子,又只能去AndroidManifest文件裏找了,找到才發現居然在C模塊裏。代碼也是又亂又臭,致使出現一大堆bug又很差找,改好一個bug又出現另外一個。整個項目從架構到代碼都是又臭又亂,開發人員只是不停地改bug,根本無法作新功能,更別談擴展了。當時,公司已經有爲不一樣客戶定製化app的需求,而現有的架構徹底沒法知足這樣的需求。所以,我決定重構,搭建一個易維護、易擴展、可定製的項目。java
我將項目分爲了四個層級:模型層、接口層、核心層、界面層。模型層定義了全部的模型;接口層封裝了服務器提供的API;核心層處理全部業務邏輯;界面層就處理界面的展現。幾個層級之間的關係以下圖所示:
下面展開說明具體的每一個層次:android
接口層
接口層封裝了網絡底層的API,並提供給核心層調用。剛開始,爲了簡單,該層的核心類我只定義了4個:json
PostEngine,請求引擎類,對請求的發送和響應結果進行處理;數組
Response,響應類,封裝了Http請求返回的數據結構;緩存
Api,接口類,定義了全部接口方法;服務器
ApiImpl,接口實現類,實現全部接口方法。微信
PostEngine將請求封裝好發送到服務器,並對響應結果的json數據轉化爲Response對象返回。Response其實就是響應結果的json數據實體類,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則實現全部Api接口了,實現代碼相似以下:
@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) {
//異常處理
}
}
實現中將請求參數和返回的類型定義好,調用PostEngine對象進行處理。
接口層的核心基本上就是這些了。
核心層
核心層介於接口層和界面層之間,主要處理業務邏輯,集中作數據處理。向上,給界面層提供數據處理的接口,稱爲Action;向下,調用接口層向服務器請求數據。向上的Action中定義的方法相似以下:
public void getCustomer(String loginName, CallbackListener<Customer> callbackListener);
這是一個獲取用戶信息的方法,由於須要向接口層請求服務器Api數據,因此添加了callback監聽器,在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的需求,所以,這裏就須要創建多個app的界面,這是一個很麻煩的事情,還好,Android Studio提供了很方便的方法能夠大大減小工做量,主要經過設置Gradle,不一樣app能夠添加不一樣的productFlavors。
界面層package的定義我也並不按照舊版的功能模塊劃分,而根據不一樣類型劃分,主要分爲如下幾個包:
其中,activity、adapter、fragment各自都有一個基類,作統一的處理,好比定義了一些共用的常量、對象和方法等。
界面層是最複雜,最容易變得混亂不堪,最容易出問題的層級。因此,從架構到代碼,不少東西都須要設計好,以及規範好,才能保證程序易維護、易擴展。後續的文章裏將會詳細分享下我在這方面的經驗。
模型層
模型層橫跨全部層級,封裝了全部數據實體類,基本上也是跟json的obj數據一致的,在接口層會將obj轉化爲相應的實體類,再經過Action傳到界面層。另外,模型層還定義了一些常量,好比用戶狀態、支付狀態等。在Api裏返回的是用一、二、3這樣定義的,而我則用枚舉類定義了這些狀態。用枚舉類定義,就能夠避免了邊界的檢查,同時也更明瞭,誰會記得那麼多一、二、3都表明什麼狀態呢。然而用枚舉類定義的話,就必須能將一、二、3轉化爲相應的枚舉常量。這裏,我提供兩種實現方式:
1.使用gson的@SerializedName標籤,好比0爲FALSE,1爲TRUE,則能夠以下定義:
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方式獲取1或0。
結束
以上就是最基本的架構了,講得比較簡單,只列了幾個核心的東西。並無進一步去擴展,擴展是下一步的事情了,後續的文章裏會慢慢展開。
本文分享自微信公衆號 - Keegan小鋼(keeganlee_me)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。