天天看點

Android項目重構之路:架構篇

去年10月底換到了新公司,做移動研發組的負責人,剛開始接手android項目時,發現該項目真的是一團糟。首先是其架構,是按功能子產品進行劃分的,本來按子產品劃分也挺好的,可是,他卻分得太細,總共分為了17個子產品,而好幾個子產品也就隻有兩三個類而已。但應用本身其實比較簡單,要按功能子產品來分的話,最多五個子產品就夠了。另外,有好多子產品劃分也很模糊,也有很多類按其功能其實可以屬于多個子產品的,也有些類定義不明确,做了不該做的事。有時候,我要找一個界面的activity,按照其功能應該屬于a子產品的,可是在a子產品裡卻找不到,于是,我隻好去androidmanifest檔案裡找了,找到才發現原來在b子產品裡。也有時候,我要找另一個界面的activity,可我看遍了所有子產品,也沒看出這個界面應該屬于哪個子產品,沒法子,又隻能去androidmanifest檔案裡找了,找到才發現竟然在c子產品裡。代碼也是又亂又臭,導緻出現一大堆bug又不好找,改好一個bug又出現另一個。整個項目從架構到代碼都是又臭又亂,開發人員隻是不停地改bug,根本沒法做新功能,更别談擴充了。當時,公司已經有為不同客戶定制化app的需求,而現有的架構完全無法滿足這樣的需求。是以,我決定重構,搭建一個易維護、易擴充、可定制的項目。

我将項目分為了四個層級:模型層、接口層、核心層、界面層。模型層定義了所有的模型;接口層封裝了伺服器提供的api;核心層處理所有業務邏輯;界面層就處理界面的展示。幾個層級之間的關系如下圖所示:

Android項目重構之路:架構篇

下面展開說明具體的每個層次:

接口層封裝了網絡底層的api,并提供給核心層調用。剛開始,為了簡單,該層的核心類我隻定義了4個:

postengine,請求引擎類,對請求的發送和響應結果進行處理;

response,響應類,封裝了http請求傳回的資料結構;

api,接口類,定義了所有接口方法;

apiimpl,接口實作類,實作所有接口方法。

postengine将請求封裝好發送到伺服器,并對響應結果的json資料轉化為response對象傳回。response其實就是響應結果的json資料實體類,json資料是有固定結構的,分為三類,如下:

event為傳回碼,0表示成功,msg則是傳回的資訊,obj是傳回的單個資料對象,objlist是傳回的資料對象數組,currentpage表示目前頁,pagesize則表示目前頁最多對象數量,maxcount表示對象資料總量,maxpage表示總共有多少頁。根據此結構,response基本的定義如下:

每個屬性名稱都要與json資料對應的名稱相一緻,否則無法轉化。obj和objlist用泛型則可以轉化為相應的具體對象了。

api接口類定義了所有的接口方法,方法定義類似如下:

apiimpl則實作所有api接口了,實作代碼類似如下:

實作中将請求參數和傳回的類型定義好,調用postengine對象進行處理。

接口層的核心基本上就是這些了。

核心層介于接口層和界面層之間,主要處理業務邏輯,集中做資料處理。向上,給界面層提供資料處理的接口,稱為action;向下,調用接口層向伺服器請求資料。向上的action中定義的方法類似如下:

這是一個擷取使用者資訊的方法,因為需要向接口層請求伺服器api資料,是以添加了callback監聽器,在callback裡對傳回的資料結果進行操作。callbacklistener就定義了一個成功和一個失敗的方法,代碼如下:

接口的實作基本分為兩步:

參數檢查,檢查參數的合法性,包括非空檢查、邊界檢查、有效性檢查等;

使用異步任務調用接口層的api,傳回響應結果。

需要注意的是,action是面向界面的,界面上的資料可能需要根據不同情況調用不同的api。

後續擴充可以在這裡添加緩存,但也要視不同情況而定,比如有些變化太快的資料,添加緩存就不太适合了。

界面層處于最上層,其核心就是負責界面的展示。

因為公司有為不同商戶定制不同app的需求,是以,這裡就需要建立多個app的界面,這是一個很麻煩的事情,還好,android studio提供了很友善的方法可以大大減少工作量,主要通過設定gradle,不同app可以添加不同的productflavors。

界面層package的定義我也并不按照舊版的功能子產品劃分,而根據不同類型劃分,主要分為以下幾個包:

Android項目重構之路:架構篇

其中,activity、adapter、fragment各自都有一個基類,做統一的處理,比如定義了一些共用的常量、對象和方法等。

界面層是最複雜,最容易變得混亂不堪,最容易出問題的層級。是以,從架構到代碼,很多東西都需要設計好,以及規範好,才能保證程式易維護、易擴充。後續的文章裡将會詳細分享下我在這方面的經驗。

模型層橫跨所有層級,封裝了所有資料實體類,基本上也是跟json的obj資料一緻的,在接口層會将obj轉化為相應的實體類,再通過action傳到界面層。另外,模型層還定義了一些常量,比如使用者狀态、支付狀态等。在api裡傳回的是用1、2、3這樣定義的,而我則用枚舉類定義了這些狀态。用枚舉類定義,就可以避免了邊界的檢查,同時也更明了,誰會記得那麼多1、2、3都代表什麼狀态呢。然而用枚舉類定義的話,就必須能将1、2、3轉化為相應的枚舉常量。這裡,我提供兩種實作方式:

使用gson的@serializedname标簽,比如0為false,1為true,則可以如下定義:

通過定義一個value,如下:

通過gson的方式,直接通路true或false就會自動序列化為1或0;如果通過第二種方式,因為沒有序列化,則需要通過getvalue方式擷取1或0。

以上就是最基本的架構了,講得比較簡單,隻列了幾個核心的東西。并沒有進一步去擴充,擴充是下一步的事情了,後續的文章裡會慢慢展開。