1. 程式人生 > >【架構】android元件化方案,讓團隊開發更有效率

【架構】android元件化方案,讓團隊開發更有效率

剛接到Leader元件化任務的時候,內心是有疑惑的。目前專案中,各種業務交雜在一起,互相跳轉、互相請求資料。分模組的過程必然是痛苦的,需要增加模組之間通的信協議。對於一個5,6人的團隊來說,全都放在一個大模組中似乎也沒啥不好,可以隨心所欲地呼叫,節約思考框架合理性的時間。

但最終讓我解除疑惑是團隊擴張的長遠考慮,未來團隊擴張到8~10人時,在同一個模組中開發不同的業務就會很亂。程式碼量2倍,掌握的難度就會超過4倍,按業務分模組一定是未來的方向。

顧名思義,元件化能夠讓開發者只需專注自己開發的元件,獨立執行自己的模組,節省編譯時間,減少因別人的問題導致工作被打斷的可能。

元件化的實現圍繞下面幾個點

1、子模組單獨編譯

2、sdk和第三方庫的版本一致性

3、資源重複定義

4、模組之間頁面跳轉

5、模組之間資料傳遞

6、模組初始化處理

1、子模組如何單獨編譯

我們希望在開發模式下,能夠單獨除錯自己的模組,編譯成獨立的apk。而在主程式釋出時,成為一個library嵌入主工程。

首先在子模組build.gradle中定義常量,來標示模組目前是否處於開發模式

兩種模式下模組AndroidManifest.xml檔案是有差別的。作為獨立執行的app,有自己的Application,要加Launcher的入口intent,作為library不需要。這個問題很好解決,寫兩個不同的AndroidManifest.xml即可,並在gradle中進行配置。

2、sdk和第三方庫的版本一致性

不同module依賴sdk版本不一致,會因相容性問題導致編譯問題。

不同module引用了同一個第三方庫的不同版本,並且這個庫沒有做到向前相容,就有可能出現方法找不到、引數不對應等問題。

所以有必要統一整個project的依賴版本。

在最外層build.gradle中定義的常量能被整個project的build.gradle檔案引用,統一的版本定義可以放在這裡。

3、資源的重複定義

說到資源的重複定義,筆者趟過坑,如果主工程和子模組中重複定義了同名的資源。

雖然編譯不會出錯,但是最後子模組中用到daddy的地方都會顯示爸爸。

編譯時子模組的資源會和主工程合併到同一個類中,所以資源重名會有問題。

但是資源也要模組化呀,總不能在底層找個統一的地方都扔在裡面,gradle提供了一個解決方案來避免重複定義的問題。

resourcePrefix "a_"

強制模組中的資源名稱帶有a_字首,否則編譯不過。

聊到這裡,我們知道了如何使用gradle獨立編譯子模組,以及如何處理分模組導致的一些問題。但是除了主工程統一排程外,模組與模組之間也需要互相調起和訪問,所以需要協議去統一,這個協議是模組間共同定義與使用的,所以寫在底層。

Paste_Image.png

4、模組之間頁面跳轉

首先想到的就是配置uri去匹配模組AndroidManifest.xml中的intentFilter來啟動相應Activity,這種方式是解耦的,但有缺點,要跳轉其它模組,得先去看別的模組的AndroidManifest.xml進行入口適配,還得研究具體Activity中的傳參設定,雖然程式碼依賴上解耦了,但是實現邏輯上沒有解耦,忍不了。需要在底層建立一個路由協議,讓使用者通過協議方便地呼叫。

用註解把需要的引數寫在路由協議的介面中。下面是moduleA提供給其它模組跳轉moduleA中頁面的介面:

其中@RouterUri表示跳轉改頁面需要匹配的uri,這個uri最終會拿去和moduleA中的

AndroidManifest.xml中對應activity的intentFilter去匹配。

為什麼用註解的方式寫介面而不是直接定義跳轉方法呢?

用註解的方式,可以把引數更直觀地展現在最醒目的方法宣告中。而寫成實現的方法,引數會被寫在方法內部,定義起來不方便,而且要帶上少量邏輯,不夠簡潔。參考retrofit框架,也是用註解方式去實現,簡潔、方便。

為什麼介面返回的是Intent,而不是直接進行頁面跳轉呢?

因為我們的專案中,實現這個跳轉可能是activity,可能是fragment,也可能startActivityForResult需要帶入一個自定義的requestCode。所以為了靈活性,直接返回Intent。

寫好了介面,還需要將介面中的引數組裝成一個可進行跳轉的Intent。使用Proxy生成類動態代理這個介面。

上面程式碼包裝了一個路由匯流排,來獲取並快取路由介面的例項。

例如:moduleB需要調起 moduleA中的ActivityA

5、模組之間的資料傳遞

每個module在底層library中用介面定義自己公開出來的方法

由匯流排進行管理

每個module需要提前在方法匯流排中傳入介面的例項(建議在Application.onCreate時),別的模組才能訪問到該方法。

moduleB訪問moduleA提供的getData方法:

FunctionBus.getFunction(FunctionA.class).getData("hi")

6、application初始化

子模組作為application時,有一些初始化的工作需要在Application.onCreate時進行。而作為library時,調不到這個onCreate。所以自己寫一個靜態方法,供主工程的Application呼叫。

主工程的Application onCreate時記得初始化子模組。

想除錯A模組,but某些功能需要依賴B

這時只需要把B模組作為library引入A。並且記得在B模組Application.onCreate時初始化一下A模組。是不是很輕量級?常用的話在gradle中設定一個開關就更方便了。

總結

大學畢業剛開始工作時,當時的Leader就表達過一個觀點,隨著團隊人越來越多,產出會越來越多,但是人均產出明顯會減少。隨著程式碼量的增多,程式碼的複雜性會呈指數上升,增加了新同學融入工作的難度。讀完這篇文章我們知道,通過元件化,新同學只需關注少量的程式碼就能快速融入工作,開發中也能更專注於自己的功能,編譯更快,bug更少。爽歪歪!