天天看點

Android項目重構之路:實作篇

IDE采用Android Studio,Demo實作的功能為使用者注冊、登入和展示一個券清單,資料采用我們現有項目的測試資料,接口也是我們項目中的測試接口。

實作上,在Android Studio分為了相應的四個子產品(Module):model、api、core、app。

model為模型層,api為接口層,core為核心層,app為界面層。

model、api、core這三個子產品的類型為library,app子產品的類型為application。

四個子產品之間的依賴設定為:model沒有任何依賴,接口層依賴了模型層,核心層依賴了模型層和接口層,界面層依賴了核心層和模型層。

項目搭建的步驟如下:

建立新項目,項目名稱為KAndroid,包名為com.keegan.kandroid。預設已建立了app子產品,檢視下app子產品下的build.gradle,會看到第一行為:

這行表明了app子產品是application類型的。

分别建立子產品model、api、core,Module Type都選為Android Library,在Add an activity to module頁面選擇Add No Activity,這三個子產品做為庫使用,并不需要界面。建立完之後,檢視相應子產品的build.gradle,會看到第一行為:

建立子產品之間的依賴關系。有兩種方法可以設定:

第一種:通過右鍵子產品,然後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

phoneNum

手機号碼

輸出樣例:

注冊接口

customer.registerByPhone

code

驗證碼

password

MD5加密密碼

登入接口

其他參數:

customer.loginByApp

loginName

登入名(手機号)

imei

手機imei串号

loginOS

系統,android為1

int

券清單

issue.listNewCoupon

currentPage

目前頁數

pageSize

每頁顯示數量

是以可以封裝成實體類,代碼如下:

上面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。具體實作如下:

簡單的實作代碼就是這樣,其實,這還有很多地方可以優化,比如,将參數為空的檢查、手機号有效性的檢查、數字型範圍的檢查等等,都可以抽成獨立的方法,進而減少重複代碼的編寫。異步任務裡的代碼也一樣,都是可以通過重構優化的。另外,需要擴充時,比如添加緩存,那就在調用Api之前處理。

核心層的邏輯就是這樣了。最後就到界面層了。

首先,界面層需要調用核心層的Action,而這會在整個應用級别都用到,是以,Action的執行個體最好放在Application裡。代碼如下:

另外,一個Activity的基類也是很有必要的,可以減少很多重複的工作。基類的代碼如下:

再看看登入的Activity:

登入頁的布局檔案則如下:

可以看到,EditText的id命名統一以edit開頭,而在Activity裡的控件變量名則以Edit結尾。按鈕的onClick也統一用toXXX的方式命名,明确表明這是一個将要做的動作。還有,string,dimen也都統一在相應的資源檔案裡按照相應的規範去定義。

注冊頁和登陸頁差不多,這裡就不展示代碼了。主要再看看券清單頁,因為用到了ListView,ListView需要添加擴充卡。實際上,擴充卡很多代碼都是可以複用的,是以,我抽象了一個擴充卡的基類,代碼如下:

這個抽象基類內建了設定資料的方法,每個具體的擴充卡類隻要再實作各自的getView方法就可以了。本Demo的券清單的擴充卡如下:

而券清單的Activity簡單實作如下:

終于寫完了,代碼也終于放上了github,為了讓人更容易了解,是以很多都比較簡單,沒有再進行擴充。

本文轉自ljianbing51CTO部落格,原文連結:http://blog.51cto.com/ljianbing/1733333 ,如需轉載請自行聯系原作者