網(wǎng)上組件化的文章很多,我本人學(xué)習(xí)組建化的過(guò)程也借鑒了網(wǎng)上先輩們的文章括勺。但大多數(shù)文章都從底層的細(xì)枝末節(jié)開(kāi)始講述放可,由下而上給人一種這門技術(shù)“博大精深”望而生畏的感覺(jué)。而我寫這篇文章的初衷就是由上而下朝刊,希望別人在閱讀的過(guò)程中能夠覺(jué)得“組件化原來(lái)也就是這幾個(gè)東西”的感覺(jué)耀里。
首先我們來(lái)看一下組件化項(xiàng)目和傳統(tǒng)項(xiàng)目的區(qū)別
在傳統(tǒng)的項(xiàng)目里
我們通常情況下會(huì)有一個(gè)commonLib的Libary模塊和一個(gè)app的application模塊,業(yè)務(wù)中的邏輯都寫在app中各個(gè)功能模塊放到不同的包下拾氓。這樣做有以下幾個(gè)主要的缺點(diǎn):
1.無(wú)論分包做的再好冯挎,隨著項(xiàng)目的增大,項(xiàng)目會(huì)逐漸失去層次感,別人來(lái)接手的時(shí)候會(huì)很吃力房官。
2.我們?cè)赿ebug一個(gè)小功能的時(shí)候每次修改代碼都需要重新build整個(gè)項(xiàng)目趾徽,這樣顯的很不合理(不知道AS的熱部署有沒(méi)有解決這個(gè)問(wèn)題)
3.多人聯(lián)合開(kāi)發(fā)在版本管理中很容易出現(xiàn)沖突和代碼覆蓋的問(wèn)題
在組件化項(xiàng)目中
除了有commonLib和app模塊外,我們按照功能劃分各個(gè)業(yè)務(wù)組件模塊(eg:微信可以劃分出chat翰守,contract孵奶,find,mine四個(gè)大模塊)蜡峰,之前的包變成現(xiàn)在的模塊了袁,增加了層次感;每個(gè)功能模塊可以單獨(dú)編譯湿颅,加快了編譯速度载绿,也為提供單元模塊測(cè)試提供了支持;多人開(kāi)發(fā)只負(fù)責(zé)自己的模塊油航,直接避免了版本管理的沖突崭庸。
在明白了組件化為我們解決的主要問(wèn)題后我們來(lái)看看需要怎么做
初步實(shí)現(xiàn)組建化其實(shí)我們最終要解決的問(wèn)題就只有2個(gè):
1.設(shè)置模塊之間的依賴,且使得業(yè)務(wù)模塊可單獨(dú)編譯--通過(guò)配置gradle即可解決
2.業(yè)務(wù)模塊之間的頁(yè)面跳轉(zhuǎn)以及通信--使用阿里開(kāi)源的ARouter即可解決
接下來(lái)我們具體來(lái)看一下如何操作
首先來(lái)看一下模塊間依賴的問(wèn)題
我們可以參照微信的四個(gè)模塊(chat,contract,find饵较,mine)來(lái)配置
首先我們項(xiàng)目基本結(jié)構(gòu)如下:
我們一共需要建6個(gè)module秽澳,除了4個(gè)功能模塊外還有一個(gè)基本的common庫(kù)和一個(gè)作為啟動(dòng)的application。
在建好項(xiàng)目后我們需要給4個(gè)module配置一個(gè)是否單獨(dú)編譯的開(kāi)關(guān):
關(guān)于開(kāi)關(guān)的配置位置這是一個(gè)問(wèn)題,我們把它添加在gradle.properties文件中,這樣我們每次修改值的時(shí)候就可以觸發(fā)gradle的重新構(gòu)建,便于我們單獨(dú)編譯module驻呐。
我們單獨(dú)編譯的開(kāi)關(guān)配置好了,現(xiàn)在我們來(lái)配置6個(gè)module之間的依賴關(guān)系:
首先芳来,為了方便各個(gè)module之間的交互我們借用了阿里的充分ARouter庫(kù)含末,所以在每個(gè)非common的庫(kù)(包括主Application)中我都強(qiáng)烈建議加入對(duì)ARouter和commonlib的依賴。
其次即舌,4個(gè)功能模塊庫(kù)我們要為它裝上我們之前配置的是否單獨(dú)編譯的開(kāi)關(guān)佣盒,我們需要修改如下2個(gè)地方:
可以看到我們要修改的就是我紅框框住的地方,當(dāng)我們的開(kāi)關(guān)打開(kāi)的時(shí)候顽聂,我們就把他當(dāng)成一個(gè)單獨(dú)的application來(lái)編譯肥惭,并且賦予它一個(gè)獨(dú)一無(wú)二的applicationId,這樣我們就可以通過(guò)剛剛在gradle.properties中配置的開(kāi)關(guān)來(lái)控制它是否單獨(dú)作為一個(gè)application來(lái)編譯紊搪。
而對(duì)于我們的入口module--app模塊我們則需要做如下的配置:
我們除了需要配置基本的ARouter以及commonlib依賴以外還需要在app模塊的gradle文件中根據(jù)開(kāi)關(guān)選擇是否需要依賴我們的功能模塊蜜葱,這個(gè)和各個(gè)功能模塊中的配置是相呼應(yīng)的。
而對(duì)于其他組件模塊耀石,重復(fù)上述步驟即可完成組件化框架的搭建:
在完成了組件化框架的搭建后我們來(lái)簡(jiǎn)單的看看框架中一些具有特色的使用方法牵囤。
我們首先來(lái)看一下各個(gè)模塊的頁(yè)面間是怎樣跳轉(zhuǎn)的。
我們之前已經(jīng)依賴了ARouter(詳細(xì)用法參照https://github.com/alibaba/ARouter),我們要用它來(lái)幫我們實(shí)現(xiàn)跳轉(zhuǎn)需要以下幾步:
跳轉(zhuǎn)的方法就如同圖2-1中顯示,我們需要標(biāo)明目標(biāo)頁(yè)面揭鳞,附帶上要傳送的參數(shù)炕贵,然后調(diào)用navigation()就可以跳轉(zhuǎn)了,不過(guò)有人問(wèn)目標(biāo)頁(yè)面怎么看著就是一個(gè)路徑野崇,它是怎樣定義的称开?
- 首先要用@Route注解標(biāo)注頁(yè)面,并在path變量中給頁(yè)面定義一個(gè)路徑
- 對(duì)于傳送過(guò)來(lái)的變量我們直接定義一個(gè)同名的字段用@Autowired變量標(biāo)注乓梨,Arouter會(huì)對(duì)該字段自動(dòng)賦值
- 最后我們還需要將該頁(yè)面注入到ARouter中(原理類似ButterKnife)鳖轰,讓他幫我們完成我們需要的工作
這樣,我們就完成了頁(yè)面間的跳轉(zhuǎn)了督禽,是不是比起我們傳統(tǒng)的方法更加簡(jiǎn)單合理脆霎?
最后我們來(lái)看一下組件間如何為彼此提供服務(wù)总处。
- 這里我想在主module中調(diào)用home組件的sayHello方法來(lái)Toast一個(gè)人的名字
- 那home里的方法怎樣才能被其他模塊(包括主模塊和其他組件模塊)調(diào)用
首先在commonlib模塊里創(chuàng)建一個(gè)暴露方法的接口狈惫,并定義接口簽名,同時(shí)繼承 Iprovider 接口
然后在home模塊中繼承commonlib里定義的接口鹦马,并實(shí)現(xiàn)簽名方法胧谈。
這里我們同樣使用Arouter的 @Router注解來(lái)提供這次服務(wù)的路由。
最后荸频,我們?cè)谄渌K使用 @Autowired 注解就可以調(diào)用該方法了
可以看到我們同樣使用了@Autowired注解來(lái)初始定baseService服務(wù)菱肖,并將頁(yè)面注入Arouter中即可調(diào)用服務(wù)中的方法,且對(duì)于服務(wù)的依賴是基于接口的依賴旭从,大大提高了其靈活性稳强!
基本組件化框架的搭建就完成了,希望認(rèn)真看完的朋友能有所收獲和悦!如有不正之處還望指正退疫!
以上項(xiàng)目的碼云地(歡迎參與改進(jìn)):
https://gitee.com/zsq519/ARouterBaseProject