組件化之開發總結

 

Android組件化探索與實踐
在Android開發中,隨着業務複雜性不斷的增長,項目的代碼量會不斷的增大,這對於項目的維護提出了更大的挑戰。Android的組件化開發就是旨在解決大型項目的可維護性、可擴展性的難題。
1、組件化簡介
組件化是大型Android項目的一個好的解決方案。經過對項目工程進行組件化,利於代碼的維護與擴展,特別是在多團隊協做開發的模式中,尤爲有效。


java

對於Android組件化的討論其實已經持續很長的一段時間了,也產生了不少種的組件化方案,不一樣的組件化方案有不一樣的利弊,可是其組件化目標基本一致,只是實現思路可能不一樣。本篇文章就是講解咱們實現的一種組件化方案。app

首先須要瞭解什麼是組件化?簡單來講,組件化就是對項目依據業務功能拆分紅不一樣的模塊,這些業務功能模塊彼此獨立,不相互依賴,既能夠獨立編譯運行,也可一塊兒打包成一個app。經過下圖來對比一下組件化的特色。框架


圖1.1傳統項目組織方式
maven

 

 

圖1.2 Android組件化方式ide

 

 

經過上圖能夠明顯的看出,傳統的項目組織形式,不一樣模塊之間會相互引用,形成耦合。而在組件化工程中,不一樣業務模塊之間是沒有相互引用關係的,彼此項目獨立。組件化

 

2、組件化目標
在瞭解了組件化的定義以後,須要明確組件化的目標主要是什麼。組件化的目標主要是解決以下幾方面的問題。
gradle

解耦合
隨着項目不斷的迭代,代碼愈來愈龐大、臃腫,這時代碼的維護就會顯得極其繁重。若是可以根據業務來對項目進行業務模塊劃分,不一樣開發人員來維護不一樣業務模塊,同時業務模塊之間彼此無關聯,這樣就方便了項目的維護。
ui

代碼複用
組件化後,能夠將一些功能組件、業務組件作成aar,上傳到maven私服,這樣便於其餘團隊經過maven來引用,快速的引入相關的功能模塊。
this

加快編譯速度、偏於開發調試
當項目很大的時候,編譯一次是很是耗時的。若是項目採用組件化,那麼業務模塊能夠做爲主module運行,這樣在開發階段,能夠只加載開發人員關心的模塊,而無需加載全部模塊,這樣會大大的提供編譯速度,同時也能夠明確問題邊界,利於bug的分析、處理。
設計

便於多團隊協同開發、維護
當不一樣團隊維護一個app時,是極容易形成代碼衝突的。組件化便可完美解決這個問題,不一樣的業務團隊維護不一樣的業務組件,業務組件之間彼此隔離,不會相互干擾。

3、組件化設計
在上一節中明確組件化須要解決的問題,本小結就來討論下如何經過組件化的設計來逐條解決上述問題。

3.1 解耦合
在傳統方式中,不一樣的module之間想要相互調用,須要經過在gradle文件中相互引用,這樣才能夠獲取到module中的類。而在組件化中,須要在不一樣模塊彼此隔離的狀況下相互調用,這樣才能達到解耦合的目的。

能夠經過路由框架來實現不一樣業務模塊之間的隔離。咱們的組件化實踐採用了阿里的ARouter。經過ARouter能夠實現Fragment的實例獲取、Activity之間的跳轉、交互等。舉例以下:

業務組件B想要跳轉到業務組件A中的Tab頁面,能夠經過路由框架跳轉:
業務組件A中TabActivity定義以下:

@Route(path = "/app/tab")
public class TabActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}





業務組件B中利用路由框架來跳轉:

ARouter.getInstance().build("/app/tab").navigation()  



能夠看到,經過路由框架,在業務組件B中,無需引入業務組件A中的TabActivity類便可實現頁面的跳轉。這樣就達到了解耦合。

組件之間頁面的跳轉能夠經過如上的方式來解決,還有一種情景,經過如上的路由方式是解決不了的,即接口的調用。例如:業務組件B想要調用登陸組件中獲取登陸信息的方法。想要實現這樣的功能,比較通用的實現方式是接口下沉。

 

 


圖3.1接口下沉方式

這種方式的缺點就是:每一個業務組件都須要把對外暴露的方法下沉到底部的組件中,這樣其實並無很好的實現解耦合。

而咱們的組件化方案則採用了一種不一樣的方式,這也是本文所論述的組件化實踐中的一個核心內容。咱們採起的方案是將業務組件拆分紅兩個模塊:對外暴露的接口模塊、業務功能模塊。以下圖所示:

 

 

圖3.2 模塊拆分

以上圖爲例,將本來的業務模塊Module A,拆分紅接口模塊Module A interface、業務模塊Module A。接口模塊的做用是對外暴露接口,而業務模塊是接口真正的實現類,其會實現Module A interface中的接口。若其餘模塊想要調用此模塊的相關功能,則只需引用其接口模塊,而無需引用其業務模塊,這樣就實現了業務模塊之間的解耦合。

剩下要解決的問題就是如何在只引用接口的狀況下,就能調用接口實現類的相關方法。咱們採用的方式是編譯期註解處理、反射等技術。詳細論述以下。

首先,須要定義兩個註解,BxBundleService、BxService。BxService的做用是標記對外暴露接口的實現類,BxBundleService的做用是標記須要注入的接口實例。以登陸模塊爲例示例以下:

登陸接口模塊對外提供的接口:

 

 


登陸業務模塊中會實現上述的接口,經過BxService註解來標記其爲實現類:

其餘業務模塊能夠在須要的時候調用登陸模塊中的方法:

 

 


其次,有了註解的標記,接下來就是註解的處理,咱們爲了提升程序的運行效率,沒有采用運行時處理註解,而是採用了編譯期間處理註解,具體以下:

1.引入編譯期註解處理類庫,在gradle文件中引入:

 

 

2. 定義Processsor,在編譯期對註解進行處理

註解處理,這點也是本組件化實踐過程當中的核心要點
3.1 遍歷BxService註解標記的類,對其生成一個輔助源文件,以登陸模塊爲例,生成以下的輔助文件

 

 

3.2 遍歷含有BxBundleService註解的類,完成BxBundleService標記的屬性對象的注入,其也是經過生成輔助源文件的方式來完成。生成的文件以下

 

 


輔助源文件的生成可使用javapoet庫來實現。這裏再也不論述。

4.流程串聯,在使用登陸模塊時,須要經過BxbankModuleBus.inject(this)方法先完成服務的注入,其實現方式以下

 

 

經過代碼能夠看出,其經過反射獲取到BxbankModuleBusInterface實例,並調用期bxbankModuleBusInject方法,此時再看上面3.2中的BxbankModuleBusInterface的實現類能夠看到,bxbankModuleBusInject方法的主要做用就是找到LoginService的全路徑名,並經過反射生成其實例,並最終將其實例注入到引用對象中。至此完成了loginService的實例注入,以後就能夠經過loginService實例來進行登陸模塊的相關調用。

經過前面的論述能夠看到模塊間只需引入模塊的接口模塊,就可完成模塊間的相互調用,達到了解耦合的目的。

3.2 代碼複用
對代碼進行模塊拆分後能夠看到,代碼已經完成了高內聚、低耦合,一些基礎的功能模塊、業務模塊能夠提供給其餘項目組來複用。

3.3 加快編譯速度、偏於開發調試
有時全量編譯整個工程是很耗時的,也是沒必要要的。例如某個開發者只負責登陸模塊,那麼其能夠排除其餘的業務模塊,而只編譯、運行登陸模塊來進行開發和維護,這樣能夠大大的提供編譯效率,提高開發體驗。能夠採用以下的技術方案來達到這個目的:

首先:在工程的build.gradle文件中定義個變量來控制組件是否能夠獨立編譯、運行

 

 


其次:在模塊組件的build.gradle文件中經過上面定義的變量來決定其是否做爲主module運行

 

 


最後:須要對源文件進行處理,由於主module的manifest文件中,應包含launcher頁面的入口,以下:

 

 

 

從配置中能夠看出,根據isModule變量的不一樣,源碼則引入不一樣的manifest文件,這樣就實現了業務組件的獨立編譯運行。

3.4便於多團隊協同開發、維護
經過以前的論述能夠看出,項目進行組件化改造以後,各個業務組件之間相互獨立,無直接的引用,這樣不一樣業務組件之間能夠進行獨立的黑盒開發、面向接口開發,而彼此不會相互依賴,極大的方便了多團隊的協同開發,減小衝突的可能行。

4、總結前面論述了組件化的定義、目標、實現思路等內容。經過以前的論述能夠看到,咱們在進行組件化探索與實踐中,主要用到的技術包括路由、編譯期註解處理、反射、gradle配置等技術、技巧,經過這些技術方案的實施,造成了咱們本身的組件化方案框架,達到了組件化的目的。 

相關文章
相關標籤/搜索