Android項目中代碼量達到一定程度,編譯將是一件非常痛苦的事情,短則一兩分鐘,長則達到五六分鐘。Android studio推出instant run由于各種缺陷一般情況下是被關閉的……
組件化開發可以有效降低代碼模塊的耦合度,使代碼架構更加清晰,同時模塊化的編譯可以有效減少編譯時間,當然總的編譯時間是不會減少的,只是App模塊化之后開發某個模塊時,只需要編譯特定模塊,可以快速編譯調試。
原理
組件化和插件化有些同學有些迷惑,簡單來說組件化是在編譯期分模塊,插件化是在運行期。一般插件化用于動態修復bug或者動態更新模塊,相對來說黑科技更多一些。
正常一個App中可以有多個module,但是一般只會有一個module是設置為application的,其他均設置為library,組件化開發就是要每個module都可以運行起來,因此在開發期間每個module均設置為application,發布時再進行合并。
實踐
本文主要介紹一下項目組件化開發過程碰到的問題和解決辦法,這里以
ModularizationApp項目為例。ModularizationApp是一個組件化的app:
-
架構
其中App是主application,ModuleA和ModuleB是兩個業務模塊,Library是基礎模塊,包含所有模塊需要的依賴庫,以及一些工具類:如網絡訪問、時間工具等。代碼結構如圖:
-
Module作為application開發
ModuleA和ModuleB是相對獨立的業務模塊,可以分別進行開發,編譯時只編譯自身,具體實現時在gradle.properties中設置變量,如:IsBuildMudle=false
在模塊的的build.gradle中:
if (IsBuildMudle.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
在主模塊的build.gradle中設置:
if (!IsBuildMudle.toBoolean()) {
compile project(':ModuleA')
compile project(':ModuleB')
} else {
compile project(':Library')
}
這樣每個module就可以獨立安裝使用了,注意在修改IsBuildMudle的值時,一定要sync gradle。
當module單獨運行和作為module運行時,其activity在manifest中設置也會不同,這里可以根據IsBuildMudle設置不同的manifest:
sourceSets {
main {
if (IsBuildMudle.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
}
}
}
分別在不同的目錄下創建manifest文件。一定要注意兩個manifest的同步問題,否則出現了莫名其名的bug,還找不到原因……
-
資源沖突問題
當分別開發模塊時,容易出資源重復命名的問題,可以在build.gradle中設置
resourcePrefix "module1_"
通過給模塊設置不同的資源前綴,可以避免重復命名。
-
Activity跳轉問題
拆分業務代碼時,自然會涉及到跨module的Activity跳轉,當單獨編譯時,自然是不能獲取到其他模塊的引用的。有幾種方式可以實現跨模塊的喚起Activity:
隱式啟動
通過設置intent-filter實現,這需要在manifest中插入大量代碼,同時也降低了安全性(其他app就可以通過這種方式隨意啟動)。
通過類名跳轉
Android業務組件化開發實踐提出了一種通過類名跳轉的方式,使用腳本生成Rlist類,比較方便快捷,但感覺不方便activity間傳遞數據。
Scheme跳轉
Scheme的方式是建立映射表,集中處理Activity,這種方式可以傳遞一定的數據。Activity傳遞大量數據時可以通過EventBus來進行傳遞(其實即使通過intent顯示啟動,也不要把大量數據放置在intent中,intent對數據大小有限制)。
在進行本次實踐時找到github上的一個url Router,同時支持http和程序內Activity跳轉,而且通過注解的方式進行,使用非常方便,于是引入到了項目中。項目地址ActivityRouter。ActivityRouter的readme中已經有比較詳細的wiki,但是還有一些需要注意的:
依賴問題:
ActivityRouter使用了apt方式,因此每個使用的module中均需要設置
apt 'com.github.mzule.activityrouter:compiler:1.1.5'
注意是每個module,在Library module中設置
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
即可。
多module問題
ActivityRouter通過注解在編譯時生成mapping,如果多個module設置依賴,就會生成多個java文件,導致源文件重復,編譯出錯,ActivityRouter目前提供了解決方法,但是還沒有正式發布版本,可以設置:
compile 'com.github.mzule.activityrouter:activityrouter:1.1.9'
apt 'com.github.mzule.activityrouter:compiler:1.1.6'
使用。使用在application中注解:
@Modules({"app", "moduleA", "moduleB"})
public class ModularizationApplication extends Application {
}
每個module中創建空java類注解:
@Module("moduleA")
public class ModuleA {
}
具體可以clone ModularizationApp查看代碼。
編譯運行
當在gradle.properties中設置IsBuildMudle=true時,可以獨立運行每個module,獨立運行調試,當設置IsBuildMudle=false,可以編譯運行整個project,注意IsBuildMudle變量設置改變時,要對gradle進行sync。
運行過程中有什么問題可以評論或者在github中提issue。
參考:
http://kymjs.com/code/2016/10/18/01
https://github.com/mzule/ActivityRouter
https://github.com/liangzhitao/ComponentizationApp
Other
歡迎關注公眾號wutongke,每天推送移動開發前沿技術文章:
推薦閱讀: