前言
開發中,我習慣性會把一個模組的功能放在一個包下,便於查詢,但煩於耦合性太高,後期維護太費勁,因此對專案進行元件化拆分勢在必行。元件化好處:便於開發,團隊成員只關注自己的開發的小模組,降低耦合性,後期維護方便等。相當於先有很多小元件,各自開發,最後組裝,成一個 app。
關係圖
app:殼工程;
module1:元件1;
module2:元件2;
common:第三方庫,公用工具、自定義 View、主題等。
效果預覽
元件化過程很容易想到一些問題,比如 module1 我想單獨除錯怎麼做?module1 有頁面需要跳轉到module2怎麼辦等。接下來,我一一探索,提供解決方案。
全域性設定 Gradle
如果有很多專案,可以設定全域性來統一管理版本號或依賴庫,這樣就不用一個個去改了,根目錄下 build.gradle 新增:
def androidSupportVersion = '25.3.1'
ext {
//編譯的 SDK 版本,如API20
compileSdkVersion = 25
//構建工具的版本,其中包括了打包工具aapt、dx等,如API20對應的build-tool的版本就是20.0.0
buildToolsVersion = "26.0.0"
//相容的最低 SDK 版本
minSdkVersion = 14
//向前相容,儲存新舊兩種邏輯,並通過 if-else 方法來判斷執行哪種邏輯
targetSdkVersion = 22
appcompatV7 = "com.android.support:appcompat-v7:$androidSupportVersion"
constraintLayout = 'com.android.support.constraint:constraint-layout:1.0.2'
}複製程式碼
其中module/build.gradle:
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
//……
}複製程式碼
資源名重名
每個 module 都有 appname,為了不讓資源名重名,可以在每個元件的 build.gradle 中增加 resourcePrefix "xxx",固定每個元件的資源字首。但是 resourcePrefix 這個值只能限定 xml 裡面的資源,並不能限定圖片資源,所有圖片資源仍然需要你手動去修改資源名。不過我更建議把圖片、 strings、 colors、dimens 等資源放到 common 去,可以防止不同的資源名字卻對應了同一資源值。
元件單獨除錯
application 與 library 切換
module1 在開發階段應該 application,等 release 後才是 library,這裡可以設定一個變數控制下,在根專案 gradle.properties 加入:
# 元件單獨除錯開關,true 可以,false 不可以,需要點選 "Sync Project"。
isDebug=false複製程式碼
module1/build.gradle:
if (isDebug.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
android {
//……
}複製程式碼
applicationId
開發階段,module1 還必須有個 applicationId:
android {
//……
defaultConfig {
// 作為library時不能有applicationId,只有作為一個獨立應用時才能夠如下設定
if (isDebug.toBoolean()){
applicationId "com.wuxiaolong.module1"
}
//……
}
}複製程式碼
入口類
到這裡還不行,還得有 AndroidManifest 設定入口類,release 後這個 AndroidManifest 不需要打包進去,新建檔案 debug,然後在 build.gradle 指定路徑:
android {
//……
sourceSets {
main {
if (isDebug.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
java {
//release 時 debug 目錄下檔案不需要合併到主工程
exclude 'debug/**'
}
}
}
}
}複製程式碼
另外,module 可能會需要使用到自定義的 Application,release 同樣也不需要打包進去,不然合併會有衝突。
元件間通訊
元件間通訊包括兩個場景:(1)UI 跳轉;(2)呼叫元件某個類的某個方法。
這裡涉及路由,何為路由,就是頁面請求,都交給它處理。網上有很多路由庫,我這裡選的是阿里的 ARouter,ARouter 能解決上面的問題,但是也遺留一個問題,我獨立執行 module1 時,想訪問 module2 頁面就做不到了,Router 不支援跨程式訪問,這個問題待定,也可能是我使用 ARouter 姿勢不對,如果您能做到,望告知。
ARouter 使用
1、common
dependencies {
//arouter
compile rootProject.ext.arouterApi
}複製程式碼
2、元件
app 和 module 都需要加入:
android {
defaultConfig {
//arouter
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName()]
}
}
}
dependencies {
//arouter
annotationProcessor rootProject.ext.arouterCompiler
}複製程式碼
3、使用
sample 列出了元件跳轉、元件跳轉-帶引數、獲取 Frgment、呼叫元件某個類的使用方法,詳見我的 GitHub 分享。
詳細使用請閱讀 ARouter,不得不吐槽,文件寫的不是一般的爛。
library 重複依賴
module1 和 module2 分別都依賴了 common,會不會導致 library 重複依賴呢,想必大家也有這個疑問了,實際上在 release 構建 APP 的過程中 Gradle 會自動將重複的 aar 包排除,APP 中也就不會存在相同的程式碼了,可以打包反編譯驗證下,我試了,確實沒有重複依賴。
ButterKnife
Attribute value must be constant
在 Android Studio 的 library 的 module 中無法使用 ButterKnife。
網上說用 R2 替代(為什麼能用 R2?),但都沒有說 R2 怎麼生成的?這篇《butterknife在library中使用問題處理》文章說使用 android-apt,確實可行,但是帶來一個新坑,發現 apply plugin: 'android-apt' 與 arouter 衝突,這時候 arouter 失效了。正確姿勢,用 Android ButterKnife Zelezny 外掛生成,手動改成 R2,clean 下就 OK,感謝群裡的小夥伴提示。
OnClick 方法
ButterKnife 還有個坑,OnClick 方法中同樣使用 R2,但是找 id 的時候使用 R,然而 library 中是不能使用 switch- case 找 id 的(原因:《在Android library中不能使用switch-case語句訪問資源ID的原因分析及解決方案》),可以使用 if-else:
@OnClick({R2.id.module1_button, R2.id.module1_button2})
public void onViewClicked(View view) {
int id = view.getId();
Log.d("wxl","id="+id);
if (id == R.id.module1_button) {
toastShow("module1_button");
} else if (id == R.id.module1_button2) {
toastShow("module1_button2");
}
}複製程式碼
當你寫 switch- case 時,Android Studio 也有提示,可以一鍵轉換成 if-else。
原始碼
最後
1、擼了一次元件化,感覺自己好菜比,好多東西還需要學習,遺留:(1)、每個 module 的配置最好有個固定模版,這樣新建 module 就不用一一配置了;(2)、關於註解與依賴注入,不明不白,導致元件間通訊花費了太多時間,後續要系統學習下這塊知識。
2、可能還有未知的坑,大家可以 Star ModularSample,我會持續更新。
3、網上元件化文章不少,但優秀的文章屈指可數,很多隻是講元件化思想,點到即止,最討厭這種半藏著半掖式分享,感覺他們在耍流氓。對於那些無私願意分享的人,我一直都是很欽佩的,因為有他們,讓我們這些後人在開發的路上不孤單無助。
4、熟悉我的朋友,可能知道我在無錫,二線城市,總感覺技術很落後,所以我一直要保持學習,不知道元件化是不是在大城市在專案中運用很普遍?據說所知,無錫元件化用的很少,理論上在一線城市會處在技術前沿。
5、很多朋友說我文章總是會一個難點講的通俗易懂,其實不知道我在易懂的背後做了多少實踐做支撐,實踐得真理,我是相信這句話的。