為什么組件化
隨著移動(dòng)互聯(lián)網(wǎng)的發(fā)展,或許中小型項(xiàng)目還可以用單工程+MVC/MVP/MVVM的架構(gòu)來(lái)完成,但當(dāng)項(xiàng)目到了一定程度之后,編譯時(shí)間 原來(lái)越長(zhǎng),測(cè)試或者開(kāi)發(fā)任何一個(gè)模塊功能都需要整個(gè)項(xiàng)目重啟運(yùn)行。
常規(guī)單工程+MVC/MVP/MVVM項(xiàng)目:
乍一看,這樣的結(jié)構(gòu)只要咱們模塊分層明確,是不存在大問(wèn)題的,但是隨著業(yè)務(wù)的快速迭代,面臨以下問(wèn)題:
1.需求瘋狂變化,上周剛討論出一套方案,你花了兩天搞定,這個(gè)時(shí)候PM告訴你,這個(gè)咱們修改或者不要了,是否想抓狂呢。
2.所有業(yè)務(wù)都在一個(gè)項(xiàng)目,不管基于什么原因,有時(shí)候咱們?yōu)榱丝焖偻瓿梢粋€(gè)功能,或多或少存在耦合,任何改動(dòng)都可能顯的比較吃力,解決了一個(gè)BUG又出現(xiàn)另外一個(gè)BUG。
3.團(tuán)隊(duì)人數(shù)達(dá)到一定程度后,并行開(kāi)發(fā)過(guò)程中,如果某個(gè)成員不小心犯錯(cuò)并且提交了代碼,可能導(dǎo)致項(xiàng)目暫時(shí)無(wú)法運(yùn)行,不得不停下來(lái)協(xié)同查找問(wèn)題,嚴(yán)重影響開(kāi)發(fā)效率
4.業(yè)務(wù)越來(lái)越多,項(xiàng)目越來(lái)越大,編譯運(yùn)行一次要10秒…20秒…1分鐘…5分鐘…累計(jì)幾個(gè)月下來(lái)的時(shí)間說(shuō)不得抽出來(lái)都可以去找個(gè)女朋友了…
基于以上問(wèn)題,咱們的組件化應(yīng)運(yùn)而生。
組件化結(jié)構(gòu)圖
對(duì)比上張圖,這里的APP主要由業(yè)務(wù)組件構(gòu)成,嚴(yán)格來(lái)說(shuō)這5個(gè)業(yè)務(wù)組件也可以是5個(gè)App,當(dāng)實(shí)現(xiàn)以上架構(gòu)圖,看看組件化的優(yōu)缺點(diǎn):
組件化優(yōu)點(diǎn)
業(yè)務(wù)組件可以單獨(dú)分配并行開(kāi)發(fā)
單個(gè)組件業(yè)務(wù)可以由開(kāi)發(fā)者自行決定采取MVC/MVP/MVVM架構(gòu)而不影響整體大局
新人接手項(xiàng)目分配任務(wù)可單獨(dú)分配某一個(gè)模塊任務(wù),不必關(guān)心整個(gè)項(xiàng)目
開(kāi)發(fā)效率提升,開(kāi)發(fā)過(guò)程僅僅需要維護(hù)開(kāi)發(fā)自己的組件內(nèi)容
若公司有多個(gè)團(tuán)隊(duì),優(yōu)秀代碼組件可快速移植復(fù)用
積累個(gè)人的組件倉(cāng)庫(kù),擺脫粘貼復(fù)制的“搬磚工”身份
測(cè)試可單獨(dú)測(cè)試某個(gè)模塊
組件化的坑
組件與組件之間的調(diào)用,數(shù)據(jù)等交互
多個(gè)組件,在使用application的時(shí)候怎辦
多個(gè)組件資源命名重復(fù)
多個(gè)組件引用不同版本的相同的庫(kù)
了解了優(yōu)缺點(diǎn),咱們進(jìn)入正式的組件化開(kāi)發(fā)集成,后續(xù)將會(huì)描述如何解決組件化的一些坑。
前文說(shuō)過(guò),咱們的5個(gè)組件可以理解為5個(gè)app,下面開(kāi)始集成。
先看看咱們的組件化效果,手機(jī)展示效果,
1:首先統(tǒng)一組件之間的版本以及第三方庫(kù)版本
利用Gradle統(tǒng)一版本號(hào),可參考 android使用Gradle統(tǒng)一配置依賴(lài)版本
2:咱們的組件又是Lib,又是application,如何控制調(diào)試,如何在主APP選擇
在config.build處新增一個(gè)布爾isBuildApp作為標(biāo)志判斷依賴(lài),true表示作為application存在,false表示lib存在
ext {
isBuildApp=false;//false:作為L(zhǎng)ib組件存在, true:作為application存在
...
}
在每個(gè)組件的build根據(jù)isBuildApp來(lái)選擇依賴(lài)
if(rootProject.ext.isBuildApp){
apply plugin: "com.android.application"
}else{
apply plugin: 'com.android.library'
}
android{
...
defaultConfig {
if(rootProject.ext.isBuildApp){
applicationId "com.allure.shop"
}
...
}
}
ibrary與application運(yùn)行時(shí)需要manifest,依然根據(jù)isBuildApp判斷
sourceSets {
main {
if (rootProject.ext.isBuildApp) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
java {
exclude 'debug/**'
}
}
}
}
資源的命名為了避免重復(fù),建議按照組件名開(kāi)頭,如Login組件,命名login_xxx,BaiDuMap組件命bd_map_xxx
可用gradle進(jìn)行強(qiáng)制檢測(cè)
resourcePrefix "login_"
主項(xiàng)目的引用
if (rootProject.ext.isBuildApp) {
compile project(':modulebase')
} else {
compile project(':modulecore:moduleLogin')
compile project(':modulecore:moduleShop')
}
解決組件與組件的交互:
方案1:可采用建立中間件的方式來(lái)統(tǒng)一管理組件之間的交互,如電影組件與首頁(yè)組件需要跳轉(zhuǎn)傳值等可采用開(kāi)源的ActivityRouter,EventBus來(lái)完成
方案2:在主項(xiàng)目APP建立統(tǒng)一的入口類(lèi),針對(duì)組件與組件的交互建立方法,實(shí)現(xiàn)接口等,但此方式有一定溝通成本,組件與組件之間的交互維護(hù)可能需要一份文檔來(lái)約束。
application的使用:
方案1:統(tǒng)一使用基礎(chǔ)庫(kù)的單例BaseApplication
方案2:反射ActivityThread
Lib與Application的切換
修改config.build里的isBuildApp屬性并且重新sync
項(xiàng)目結(jié)構(gòu)圖:
作為組件Lib
作為單獨(dú)的application
總結(jié)
組件化技術(shù)難度不大,難點(diǎn)在于業(yè)務(wù)的解耦。具體是否選擇組件化方式還是要根據(jù)項(xiàng)目大小來(lái)確定。 當(dāng)然采取了組件化是極好的。






