前言
- 什么是模塊化
項目由多個模塊構成,模塊間解耦、可重用,模塊可通過aar依賴。每個模塊都可以獨立運行。 - 為什么要模塊化
當項目越來越復雜,體積也變得臃腫,為了降低復雜性和耦合度、提高模塊重用性、單模塊運行提高編譯打包效率等等,模塊化是很好的解決方案。
改造目標
-
項目拆分為多個子工程,大概有三類:基礎組件、業務模塊、聚合業務模塊的app模塊.結構圖如下:
perfect.png
其中app模塊是application工程,其他模塊都是library工程,library工程可以打成aar上傳maven,使用maven依賴。
- 業務模塊之間通過路由、ioc服務實現通信,減少相互依賴,降低耦合性。
- 業務模塊可以獨立運行,開發期間只需運行自己的模塊,減少編譯打包時間。
遇到的問題
拆分不徹底或重復資源
我加入項目的時候,很多業務模塊已經從app模塊拆分出來,但主要是代碼移動,其對應的so,資源文件,manifest聲明卻在app模塊或base模塊,而且app啟動時的各個組件初始化也分布在很多地方。在嘗試獨立運行業務模塊時常常會出現缺少組件或找不到類編譯時或運行時報錯。另外,由于子工程是由原單一工程拆分而出的,有些資源文件或類產生了重復,增大了apk體積。-
模塊間依賴關系復雜
上面的架構圖是理想狀況,但實際項目大概是這樣的:
real.png
可以看到,很多業務模塊依賴別的業務模塊,而且依賴層級很深。這樣就違背了模塊化改造的初衷,耦合性并沒有降低多少,各個業務模塊也不能獨立開發,修改代碼牽一發而動全身。而且由于編譯時要處理各個模塊的依賴關系導致編譯時間的大幅提高。
底層模塊耦合業務
由于一些歷史原因,base模塊下的幾個模塊中有業務相關代碼,可能經常需要修改。這就導致了其不能打成aar放在maven上,只能以源碼形式進行依賴。base模塊膨脹
各個業務模塊之間往往需要通信,而且也會有很多共同依賴的資源文件。所以不能避免的需要將一些bean類和資源文件放置在base模塊中。長此以往,base模塊會變得越來越大。
解決方案
- 模塊拆分
我覺得可以遵守以下幾點原則: - 要把每個模塊看成獨立的app:每個模塊的所有資源(.java、resources、manifest聲明、lib庫、so文件)都必須拆分到自己的模塊.可以通過能否獨立運行來校驗是否有遺漏.
- 最小作用域:對于java類和資源文件,盡量做到最小作用域,能放到上層業務模塊內就不要放到下層公共依賴工程中.
- 命名規范:資源文件最好加上模塊名prefix(可以在gradle文件中設置resourcePrefix來警告不符規范的資源),另外可以通過腳本來找重名文件,去除重復.
- 模塊間通信
要解決模塊間的依賴,最重要的就是模塊間通信,通過模塊通信方式來減少直接依賴,我們項目現在主要采用了以下的通信方法: - activity路由
關于這個網上已經有了很多文章,我們項目的實現方法也類似.通過一段字符串(如/modulea/DemoActivity
)來標志某個activity,然后通過路由框架來獲取activity的class,實現跳轉. - ioc服務
除了activity跳轉肯定還有大量其他需求,我們項目使用了ioc服務來完成.(此服務與android原生service概念類似,但并非android原生的service).簡單的說就是在下層公共模塊中定義一個功能接口(或抽象類)serviceA,然后在上層模塊moduleA中創建了serviceA的實現serviceAImpl,上層模塊moduleB(不依賴模塊moduleA)通過ioc框架獲取serviceA后就可得到真正的實現類.
每個模塊都可以把自己需要被其他模塊調用到的功能以服務的方式提供出來,而其他模塊只要有功能接口就可以使用服務.
這個ioc框架的實現原理也比較簡單,就是通過注解標注出功能接口實現類,然后利用注解處理器在編譯時生成記錄接口與實現對應關系的輔助類,在app啟動時加載這些輔助類.這樣ioc框架就能通過功能接口找到實現類了.和阿里的arouter類似 - 基礎組件業務無關
從后期優化、維護方便等角度來說,網絡、圖片加載、持久化等基礎組件都應該是業務無關的。所以對于這些組件中耦合業務的情況應該盡早重構修改。最好是將這些基礎組件獨立倉庫,獨立版本號,通過maven依賴來使用。如第一張圖所示,可以在上層業務模塊與基礎組件中間的base模塊中引入基礎組件,并進行一些業務相關的配置。 - 合理劃分模塊
對于base模塊膨脹的問題,其實關鍵還在于業務模塊間劃分不明確,導致很多view、業務組件需要重用。模塊間通信只能解決一部分問題,最主要的還是要明確模塊間要有明確的邊界、合理劃分模塊,盡量讓每個模塊間獨立起來,減少通信需求。
本文只是我們項目和我的一些想法、做法,有什么意見還望大家指正。