前言
Android的開發(fā)生態(tài)系統(tǒng)發(fā)展迅速,在開發(fā)Android的幾年的時間里,用來構(gòu)建Android應(yīng)用的架構(gòu)與技術(shù)一直在不斷進(jìn)化。隨著項目的不斷更新迭代,應(yīng)用的架構(gòu)也有不一樣的變化。由于開發(fā)人員的數(shù)量、項目的業(yè)務(wù)復(fù)雜度、需求的開發(fā)時間、應(yīng)用的使用量級,使用的技術(shù)架構(gòu)也不相同。沒有最好的架構(gòu),只有最合適的。通過設(shè)計使程序模塊化,做到模塊內(nèi)部的高聚合和模塊之間的低耦合。這樣做的好處是使得程序在開發(fā)的過程中,開發(fā)人員只需要專注于一點,提高程序開發(fā)的效率,便于項目的后期維護(hù)。下面總結(jié)及匯總一下目前Android使用的主要應(yīng)用架構(gòu)及其優(yōu)缺點和使用的學(xué)習(xí)心得,如有不對之處,歡迎交流糾正。
還記得以前學(xué)生時代學(xué)習(xí).NET的時候,第一次接觸到項目架構(gòu)叫三層架構(gòu)。應(yīng)用層、業(yè)務(wù)邏輯層及數(shù)據(jù)訪問層。mvc的思想其實也一樣,都是一種軟件設(shè)計典范,用一種業(yè)務(wù)邏輯、數(shù)據(jù)、界面顯示分離的方法組織代碼,在改進(jìn)和個性化定制界面及用戶交互的同時,不需要重新編寫業(yè)務(wù)邏輯。Android的項目設(shè)計本身也是采用了mvc的設(shè)計思想。
視圖層(View)?
一般采用XML文件進(jìn)行界面的描述,使用的時候可以非常方便的引入。同時便于后期界面的修改。邏輯中與界面對應(yīng)的id不變化則代碼不用修改,大大增強(qiáng)了代碼的可維護(hù)性。
控制層(Controller)?
Android的控制層主要就是Activity層。相關(guān)View層交互觸發(fā)及數(shù)據(jù)展示邏輯都在Activity中進(jìn)行編碼。
模型層(Model)
我們通常針對業(yè)務(wù)數(shù)據(jù),都會定義好對應(yīng)的Model層。數(shù)據(jù)庫的操作、對網(wǎng)絡(luò)等的操作都應(yīng)該在Model里面處理,當(dāng)然對業(yè)務(wù)計算等操作也是必須放在的該層的
所以一直以來我們使用Android默認(rèn)的項目結(jié)構(gòu)開發(fā),主要都是在采用mvc的架構(gòu)思想。
優(yōu)點:?適用了簡單的頁面展示,業(yè)務(wù)邏輯不復(fù)雜。開發(fā)效果高,代碼層級也簡單易懂
缺點:?當(dāng)業(yè)務(wù)復(fù)雜時,Activity非常臃腫,不便于維護(hù)及測試
mvp這是目前我們項目中主要采用的應(yīng)用架構(gòu)方式,MVP從更早的MVC框架演變過來,與MVC有一定的相似性:Controller/Presenter負(fù)責(zé)邏輯的處理,Model提供數(shù)據(jù),View負(fù)責(zé)顯示。mvp架構(gòu)的演變,解決了Activity代碼臃腫的問題,當(dāng)我們將Activity復(fù)雜的邏輯處理移至另外的一個類(Presenter)中時,Activity其實就是MVP模式中的View,它負(fù)責(zé)UI元素的初始化,建立UI元素與Presenter的關(guān)聯(lián)(Listener之類),同時自己也會處理一些簡單的邏輯(復(fù)雜的邏輯交由 Presenter處理)。項目開發(fā)中,UI是容易變化的,且是多樣的,一樣的數(shù)據(jù)會有N種顯示方式;業(yè)務(wù)邏輯也是比較容易變化的。為了使得應(yīng)用具有較大的彈性,我們期望將UI、邏輯(UI的邏輯和業(yè)務(wù)邏輯)和數(shù)據(jù)隔離開來,而MVP是一個很好的選擇。在MVP模式里通常包含3個要素(加上View interface是4個):
View:負(fù)責(zé)繪制UI元素、與用戶進(jìn)行交互(在Android中體現(xiàn)為Activity)
Model:負(fù)責(zé)存儲、檢索、操縱數(shù)據(jù)(有時也實現(xiàn)一個Model interface用來降低耦合)
Presenter:作為View與Model交互的中間紐帶,處理與用戶交互的負(fù)責(zé)邏輯。
View interface:需要View實現(xiàn)的接口,View通過View interface與Presenter進(jìn)行交互,降低耦合,方便進(jìn)行單元測試
優(yōu)點:
Model與View完全分離,修改互不影響
更高效地使用,因為所有的邏輯交互都發(fā)生在一個地方—Presenter內(nèi)部
一個Preseter可用于多個View,而不需要改變Presenter的邏輯(因為View的變化總是比Model的變化頻繁)。
更便于測試。把邏輯放在Presenter中,就可以脫離用戶接口來測試邏輯(單元測試)
缺點:需要拿捏好Presenter、View interface的顆粒度設(shè)計,容易出現(xiàn)Presenter過于簡單或則復(fù)雜化。
MVVM可以算是MVP的升級版,其中的VM是ViewModel的縮寫,ViewModel可以理解成是View的數(shù)據(jù)模型和Presenter的合體,ViewModel和View之間的交互通過Data Binding完成,而Data Binding可以實現(xiàn)雙向的交互,這就使得視圖和控制層之間的耦合程度進(jìn)一步降低,關(guān)注點分離更為徹底,同時減輕了Activity的壓力
View(視圖層)采用XML文件進(jìn)行界面的描述;
Model(模型層)通過網(wǎng)絡(luò)和本地數(shù)據(jù)庫獲取視圖層所需數(shù)據(jù);
ViewModel(視圖-模型層)負(fù)責(zé)View和Model之間的通信,以此分離視圖和數(shù)據(jù)。
View和Model之間通過Android Data Binding技術(shù),實現(xiàn)視圖和數(shù)據(jù)的雙向綁定;ViewModel持有Model的引用,通過Model的方法請求數(shù)據(jù);獲取數(shù)據(jù)后,通過Callback(回調(diào))的方式回到ViewModel中,由于ViewModel與View的雙向綁定,使得界面得以實時更新。同時,界面輸入的數(shù)據(jù)變化時,由于雙向綁定技術(shù),ViewModel中的數(shù)據(jù)得以實時更新,提高了數(shù)據(jù)采集的效率。
采用ViewModel解決MVP中View(Activity)和Presenter相互持有對方應(yīng)用的問題,界面由數(shù)據(jù)進(jìn)行驅(qū)動,響應(yīng)界面操作無需由View(Activity)傳遞,數(shù)據(jù)的變化也無需Presenter調(diào)用View(Activity)實現(xiàn),使得數(shù)據(jù)傳遞的過程更加簡潔,高效。
推薦教程:
優(yōu)點:
雙向綁定技術(shù),當(dāng)Model變化時,View-Model會自動更新,View也會自動變化。很好做到數(shù)據(jù)的一致性
Google官方支持databing,易于集成
缺點:
數(shù)據(jù)綁定使得 Bug 很難被調(diào)試
數(shù)據(jù)雙向綁定不利于代碼重用及擴(kuò)展
代碼的閱讀性降低
google在官方示例中給出了一系列不同架構(gòu)的app實現(xiàn),項目目的是通過展示各種架構(gòu)app的不同方式來幫助開發(fā)者解決架構(gòu)問題。項目中通過不同的架構(gòu)概念及方式實現(xiàn)了功能相同的app。
使用RXJAVA對數(shù)據(jù)流進(jìn)行處理,并且通過Repository進(jìn)行數(shù)據(jù)的集中管理,通過協(xié)議類XXXContract來對View和Presenter的接口進(jìn)行內(nèi)部繼承,在presenter的實現(xiàn)類中,可以對Model數(shù)據(jù)進(jìn)行操作。實例中,數(shù)據(jù)的獲取、存儲、數(shù)據(jù)狀態(tài)變化都是model層的任務(wù),presenter會根據(jù)需要調(diào)用該層的數(shù)據(jù)處理邏輯并在需要時將回調(diào)傳入。這樣model、presenter、view都只處理各自的任務(wù),實現(xiàn)單一責(zé)任原則。
推薦教程:
隨著項目的推進(jìn),及企業(yè)業(yè)務(wù)的發(fā)展。有一天可以發(fā)現(xiàn)團(tuán)隊內(nèi)部需要開發(fā)多個APP,且多個APP中存在相同的業(yè)務(wù)模塊,一開始的做法為了趕項目進(jìn)度可能就是黏貼復(fù)制,到后面就慢慢發(fā)現(xiàn)越來越吃力,重復(fù)勞動。
慢慢隨著時間的推移,惡性循環(huán)。慢慢發(fā)現(xiàn)項目代碼結(jié)構(gòu)混亂、層次不清,各業(yè)務(wù)技術(shù)方案不統(tǒng)一;甚至連基本的包結(jié)構(gòu)也是胡亂不堪,都是不停地往上堆砌代碼添加新功能,前人挖坑后人填。可見組件化對于不斷迭代的項目有著深遠(yuǎn)的意義
避免重復(fù)造輪子,提高開發(fā)效率
減低耦合度,提高復(fù)用性
保持團(tuán)隊的技術(shù)方案統(tǒng)一性
便于維護(hù)升級
通常項目中常用的結(jié)構(gòu)如下:
看似沒什么問題,但通常我們的一些庫都是以代碼的形式集成在代碼中,隨著項目推進(jìn),慢慢發(fā)現(xiàn)一些比較嚴(yán)重的問題。
業(yè)務(wù)代碼侵入組件代碼中 (例如一些全局的網(wǎng)絡(luò)返回響應(yīng),直接在庫中編碼等)
團(tuán)隊內(nèi)部沒約束,各自集成不同的基礎(chǔ)庫(例如圖片加載有的用Glide,有的用ImageLoader)
部分第三方組件停止更新,項目代碼耦合高,替換新方案難
所以在實際設(shè)施組件化的過程中,建議參考:
獨立library庫(Common基礎(chǔ)組件),避免在主工程中直接以代碼集成,使用aar方式引用
第三方的庫調(diào)用最好再裝一層接口,以便后續(xù)維護(hù)升級
有成員專門負(fù)責(zé)維護(hù),可以以SDK的方式提供業(yè)務(wù)層的調(diào)用
隨著項目邏輯不斷的增加,慢慢是不是發(fā)現(xiàn)代碼編譯速度是不是越來越慢?(PS:我們目前項目編譯一次2分鐘,且已是經(jīng)過一些優(yōu)化處理)
另外當(dāng)團(tuán)隊內(nèi)部有多個項目時,是不是經(jīng)歷過產(chǎn)品經(jīng)理讓你把項目A的某個功能移到項目B去,這個時候… …
業(yè)務(wù)模塊化的作用性就很明顯了
業(yè)務(wù)模塊間避免耦合,提高復(fù)用性
業(yè)務(wù)模塊獨立編譯運行