前言
前一段時間看到JessYan的一篇文章,分享他的MVP開源框架,我相信大多數(shù)人應(yīng)該都還有印象,不得不說這個框架確實很棒,感謝JessYan的開源和分享??蚣茈m然不是項目的核心,但卻是項目的基礎(chǔ)。一個好的項目框架,能幫助你快速地開始企業(yè)級項目開發(fā)。本人經(jīng)過對MVPArms的研究考量并結(jié)合自己的想法與實際開發(fā)過程得到Atoms-MVP。
項目已開源Github,完全組件化的項目框架Atoms-mvp
什么是組件化
組件化就是將一個完整的App按照關(guān)注點分離成多個組件,使得每個組件成為單獨的個體,做到組件內(nèi)部的高聚合和組件之間低耦合。
為什么我們要組件化?
宏觀上講,組件化使開發(fā)人員更加專注于各模塊的開發(fā),使團(tuán)隊成員更加方便迭代升級和維護(hù),管理者也更容易統(tǒng)籌帷幄,規(guī)范項目層次和結(jié)構(gòu)統(tǒng)一。微觀上講,組件化必將對基礎(chǔ)庫下沉從而提高復(fù)用,這也是項目框架演變進(jìn)化過程中的的核心思想,對于子模塊一個蘿卜一個坑,互相不直接依賴,所以不用擔(dān)心變更帶來的風(fēng)險。從根本上避免一個小小的改動牽連多處需要修改,導(dǎo)致回歸整個App測試。對于測試同學(xué)而言,能有效的減少測試的時間,原有的業(yè)務(wù)不需要再次進(jìn)行功能測試,只需專注于發(fā)生變化的業(yè)務(wù),以及最終的集成測試即可
Atoms-mvp組件化過程
1.面向開發(fā)過程,維護(hù)成本,學(xué)習(xí)成本?;睘楹?,less is more,高擴(kuò)展性為宗旨,使新手也能快速搭建自己的組件化項目
2.基礎(chǔ)庫下沉,只下沉最核心最必須,絕不拖泥帶水,納污藏穢。
2.弱化了Dagger2的使用頻率,因為這對于一些新手來說Dagger2可能不是很好理解,排錯不是很好,但是對于一些頻繁使用到的Dagger代碼我做了優(yōu)化,省去了大量重復(fù)代碼,幫助團(tuán)隊加快開發(fā)速度。
3.網(wǎng)絡(luò)請求方面使用Rxjava,okhttp,retrofit組合式框架但是并沒有使用RxCache處理緩存,因為我覺得這樣會加重開發(fā)成本,增加編碼量和維護(hù)成本,其次Okhttp本身是自帶緩存策略的,我們可以到后期真正需要的時候再使用緩存框架
4.在設(shè)計架構(gòu)時,將最原始,最需要,最重要的庫打入baseLib封裝成基礎(chǔ)庫,比如網(wǎng)絡(luò),support,依賴注入型框架dagger,以及和view相關(guān)的butterknife,或者其他的一些基礎(chǔ)庫,開發(fā)者可以自行擴(kuò)展。目的是將這些充斥于整個界面相關(guān)的業(yè)務(wù)邏輯集成到最底層。往上一層封裝整個APP需要的公共服務(wù)。其中包括CommonSDK用來承上啟下,并提供ARouter路由框架,或者使用360Replugin插件化框架,為組件之間解耦做鋪墊,開發(fā)者可視情況而定二選其一。以及業(yè)務(wù)服務(wù)庫和公共UI庫,統(tǒng)一整個APP的UI風(fēng)格方便后期統(tǒng)一調(diào)整。再往上就是App的核心組件,各組件依賴公共層,組件之間絕對分離。最后整合在一起完美融合,形成一個APP應(yīng)用系統(tǒng)
本項目特點
1.支持路由框架和插件劃框架比如Arouter,RePlugin等
2.動態(tài)代理Application生命周期,各組件可做具體實現(xiàn),使得子Module間接地?fù)碛蠥pplication,能夠在子module中初始化相對當(dāng)前nodule的的第三方庫。
3.各模塊可配置單獨的ServiceApi,擁有屬于自己獨立的Api接口,同時還支持不同host場景
4.各組件數(shù)據(jù)傳輸面向接口不直接依賴于對象,使組件化解耦更徹底,做到完全組件化。在下面我會一一講到。
組件化的關(guān)鍵點
代碼隔離
代碼隔離同樣也是代碼解耦,每個組件之間代碼互不侵入,互不依賴,團(tuán)隊之間應(yīng)具備規(guī)范的意識。除了人為上的約束,IDE工具gradle也為我們提供了很好的代碼隔離語法,從AS3.0開始類庫依賴出現(xiàn)了四種新語法如下:
implementation:對應(yīng)以前的compile。與compile的區(qū)別在于使用implementation在編譯期間只對當(dāng)前宿主可見,對其他宿主隔離。同時它還有一個好處是能夠加快編譯速度。打個比方如果宿主使用implementation引用庫的話,當(dāng)宿主發(fā)生變化重新編譯時,庫不需要再編譯,只需要編譯這個宿主。而如果你使用的是compile引用庫的話,那么兩者都需要重新編譯。兩者相比較推薦使用implementation。
compileOnly:這個語法就很有意思了,它的作用是依賴的類庫只參與編譯,而不會打包進(jìn)Apk。應(yīng)用場景:子Module中引入于父親Module相同的庫可使用compileOnly ,比如下面這個例子
子Module
compileOnly "com.alibaba:arouter-compiler:1.1.4"
compileOnly "com.jakewharton:butterknife-compiler:8.8.1"
compileOnly 'com.google.dagger:dagger-compiler:2.15'
父Module
api "com.alibaba:arouter-api:1.1.4"
api "com.jakewharton:butterknife:8.8.1"
api "com.google.dagger:dagger:2.15"
注意,如果你引入進(jìn)來的是一個Module那么請注意父Module也應(yīng)該有相同的引入,但是你不能調(diào)用這個Module的資源文件,否則編譯運(yùn)運(yùn)行的時候會報錯。如果您在其他模塊以compile的方式依賴了相同lib,最終在打包過程中可能會出現(xiàn)重復(fù)代碼,建議您采用compileOnly解決重復(fù)依賴的問題
runtimeOnly: 從上圖可以看出,在代碼隔離效果上,runtimeOnly的效果是最好的!在引用子模塊最好選擇runtimeOnly,防止主Module調(diào)用子Module的代碼和資源。
其次我再補(bǔ)充說明一下資源文件隔離。雖然上面解決了代碼隔離但是對于資源文件并沒有控制,其他宿主還是能夠訪問下級的資源文件,為了避免編譯時沖突,可為資源名增加一個前綴,約束資源文件的命名規(guī)范。
android {
resourcePrefix "gank_" //給 Module 內(nèi)的資源名增加前綴, 避免資源名沖突
}
獨立的ServiceAPI
有些項目可能有多baseUrl的需求,這種情況Retrofit官方給了兩種解決方案,如下。
第一種:在 @Get , @Post注解中不僅可以傳相對路徑,還可以傳全路徑
第二種:將全路徑以參數(shù)@Url的形式傳遞給接口
獨立的Application
對于有些子模塊來說,它有屬于自己依賴的第三方庫,有些第三方庫需要在Application中初始化,而一個應(yīng)用程序的Application對象只有一個,每個組件又全部分離出去了,那么如何才能各組件共享?在Atoms-MVP中提供了解決方案。通過代理方式,委派一個AppDelegate對象去代理Application的生命周期。各各子模塊只需在Manifest文件中定義 meta標(biāo)簽,指定真實被調(diào)用的Application生命周期類名,由Appdelegate創(chuàng)建時通過反射的手段初始化。貼一張圖方便理解
數(shù)據(jù)傳遞
在組件化項目中,每個組件都是相對獨立,那么他們之間如何進(jìn)行數(shù)據(jù)傳遞呢?首先想到的是Intent、sp、file、廣播、內(nèi)容提供者等這些常見的數(shù)據(jù)傳遞方式,但是剛剛說了組件之間是相對獨立的,不能直接把實體類傳遞過去,因為在完全解耦的組件化項目中,實體類不會下沉放到公共庫,也不會在多個組件之間存在依賴關(guān)系,只出現(xiàn)在于屬于它們自己的組件當(dāng)中。那么如何將實體類也完全解耦呢?Atoms-mvp提供了一套解決方案,每個組件如果需要對外提供數(shù)據(jù)傳遞,那么統(tǒng)一在CommonService組件中聲明向外提供服務(wù)接口,具體的實現(xiàn)由需要傳遞數(shù)據(jù)的組件負(fù)責(zé),數(shù)據(jù)接收者只需要聲明這個接口,再調(diào)用接口中定義的方法獲取數(shù)據(jù)就能完成跨模塊之間的數(shù)據(jù)傳遞。這樣做使得組件之間不直接指引,避免各組件之間的類出現(xiàn)互相指引的關(guān)系,把原有的一對多的依賴變成了一對一的依賴,CommonService相當(dāng)于一個中介者,來處理各組件之間需要交流的角色。另一方面這是一種很好的思想,想像一下如果沒有中間件,那各組件之間數(shù)據(jù)傳遞相互指引很有可能就會出現(xiàn)相互纏繞導(dǎo)致耦合嚴(yán)重,一處修改,多出受災(zāi)。中間件的好處能夠降低變更帶來的風(fēng)險,定義好通信協(xié)議,由組件實現(xiàn)或調(diào)用。大多數(shù)情況下變更的總是實現(xiàn),接口相對很少變更,即使變更也有辦法兼容。所以它能夠?qū)箻I(yè)務(wù)邏輯發(fā)生變化帶來的風(fēng)險。


總結(jié)
Android應(yīng)用的架構(gòu),根據(jù)不同的應(yīng)用場景和復(fù)雜程度使得技術(shù)架構(gòu)也有不同,架構(gòu)沒有好壞之分,只要適用于自己的業(yè)務(wù)就是好架構(gòu),每一次的重構(gòu)每一次的更新都是為了節(jié)省人力和成本,提高開發(fā)效率。如果您正打算使用組件化框架完全可以把我的項目搬過去,改一改包名即可。同時Atoms-mvp也可以作為大家在進(jìn)行組件化時的參考資料,如果您覺得我的文章寫的不錯,對您有幫助請為我點贊。
Atoms-mvp項目地址:https://github.com/xwc520/Atoms-mvp
參考文檔:
http://www.itdecent.cn/p/1c5afe686d75
http://www.itdecent.cn/p/f671dd76868f
關(guān)于我Vea