問(wèn)題:實(shí)際業(yè)務(wù)變化快,而工程內(nèi)各個(gè)功能模塊耦合度太高,不能對(duì)功能模塊進(jìn)行快速方便地拆分或組裝。團(tuán)隊(duì)共同開(kāi)發(fā)中,可能一個(gè)文件同時(shí)被多人修改,導(dǎo)致每次更新提交代碼都需要消耗大量時(shí)間去merge代碼。每次修改,都需要進(jìn)行功能測(cè)試和系統(tǒng)測(cè)試。
目的:解決以上問(wèn)題,使項(xiàng)目可以靈活配置,功能模塊完全解耦,實(shí)踐組件化之路。
實(shí)現(xiàn):在之前的開(kāi)發(fā)中,一個(gè)應(yīng)用程序,我們將全部功能模塊都寫(xiě)在工程app包中。實(shí)踐組件化,我們將各個(gè)功能模塊獨(dú)立出來(lái),最終以依賴(lài)包的形式整合到app主Module中去。在這里我寫(xiě)了個(gè)項(xiàng)目demo,簡(jiǎn)單分了幾個(gè)功能模塊,應(yīng)用結(jié)構(gòu)如下圖所示:

說(shuō)明:每一個(gè)組件module是一個(gè)子工程,子工程可以依賴(lài)基礎(chǔ)庫(kù)baselibrary可獨(dú)立運(yùn)行;也可以作為主工程的依賴(lài)庫(kù)。
具體實(shí)現(xiàn):1:配置項(xiàng)目的buildscript,如下圖所示:

關(guān)于butterknife的配置及用法:http://jakewharton.github.io/butterknife,butterknife8支持在lib庫(kù)中注解。
2:在主app module gradle中如下配置:
applyplugin:'com.android.application'
applyplugin:'android-apt'
android {
? ? compileSdkVersion COMPILE_SDK_VERSION as int
? ? buildToolsVersion BUILD_TOOLS_VERSION
? ? defaultConfig {
? ? ? ? applicationId APPLICATION_ID
? ? ? ? minSdkVersion MIN_SDK_VERSIONas int
? ? ? ? targetSdkVersion TARGET_SDK_VERSIONas int
? ? ? ? versionCode 1
? ? ? ? versionName "1.0"
? ? }
? ? signingConfigs {
? ? ? ? debugConfig {
? ? ? ? ? ? storeFile file("***.jks")
? ? ? ? ? ? storePassword "******"
? ? ? ? ? ? keyAlias "*****"
? ? ? ? ? ? keyPassword "******"
? ? ? ? }
? ? releaseConfig {
? ? ? ? storeFile file("******.jks")
? ? ? ? storePassword "********"
? ? ? ? keyAlias "*****"
? ? ? ? keyPassword"*******"
? ? }
}
}
?buildTypes {
? ? ? ?release {
? ? ? ? ?minifyEnabled false
? ? ? ? ?proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
? ? ?}
? }
dependencies {
if(!isDebug.toBoolean()) {//各個(gè)模塊作為庫(kù)加載
compile project(':loginmodule')
compile project(':startmodule')
compile project(':homemodule')
compile project(':msgmodule')
}else{//各模塊獨(dú)立運(yùn)行
compile project(':baselibrary')
}
//router
apt'com.github.mzule.activityrouter:compiler:1.1.7'
}
說(shuō)明:關(guān)于activityrouter的配置及使用,在后面會(huì)說(shuō)到。
3:baselibrary作為各個(gè)模塊共同依賴(lài)的基礎(chǔ)庫(kù),其gradle配置如下:
applyplugin:'com.android.library'
applyplugin:'com.jakewharton.butterknife'
applyplugin:'android-apt'
android {
compileSdkVersion24
buildToolsVersion"25.0.2"
defaultConfig {
minSdkVersion15
targetSdkVersion24
versionCode1
versionName"1.0"
}
buildTypes {
release {
minifyEnabledfalse
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'],dir:'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
excludegroup:'com.android.support',module:'support-annotations'
})
compile'com.android.support:appcompat-v7:24.2.1'
compile'com.jakewharton:butterknife:8.5.1'
apt'com.jakewharton:butterknife-compiler:8.5.1'
compile'com.github.mzule.activityrouter:activityrouter:1.2.2'
}
4:在子工程模塊gradle配置如下(以homemodule為例):
if(isDebug.toBoolean()) {
applyplugin:'com.android.application'
}else{
applyplugin:'com.android.library'
}
applyplugin:'com.jakewharton.butterknife'
applyplugin:'android-apt'
android {
compileSdkVersion24
buildToolsVersion"25.0.2"
defaultConfig {
minSdkVersion15
targetSdkVersion24
versionCode1
versionName"1.0"
testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabledfalse
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
}
}
sourceSets {
main{
if(isDebug.toBoolean()) {
manifest.srcFile'src/debug/AndroidManifest.xml'
}else{
manifest.srcFile'src/release/AndroidManifest.xml'
}
}
}
resourcePrefix"home_"
}
dependencies {
compile fileTree(dir:'libs',include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
excludegroup:'com.android.support',module:'support-annotations'
})
compile project(':baselibrary')
apt'com.jakewharton:butterknife-compiler:8.5.1'
//router
apt'com.github.mzule.activityrouter:compiler:1.1.7'
}
說(shuō)明:當(dāng)module單獨(dú)運(yùn)行和作為module運(yùn)行時(shí),其activity在manifest中設(shè)置也會(huì)不同,這里可以根據(jù)isDebug設(shè)置不同的manifest。當(dāng)分別開(kāi)發(fā)模塊時(shí),容易出資源重復(fù)命名的問(wèn)題,可以在build.gradle中設(shè)置resourcePrefix "home_",通過(guò)給模塊設(shè)置不同的資源前綴,可以避免重復(fù)命名。
Activity跳轉(zhuǎn)問(wèn)題
從上面的配置中,可以看到,項(xiàng)目引入了apt'com.github.mzule.activityrouter:compiler:1.1.7',我們?yōu)槭裁词褂肁ctivityRouter呢,當(dāng)我們把各個(gè)功能模塊抽成獨(dú)立的lib的時(shí)候,各個(gè)模塊之間難免要進(jìn)行Activity的跳轉(zhuǎn)及傳參。我們不能再像以前那樣直接通過(guò)startActivity來(lái)實(shí)現(xiàn)跳轉(zhuǎn)了。關(guān)于ActivityRouter的配置及用法:https://github.com/mzule/ActivityRouter
使用在application中注解:@Modules({"app","homeModule","loginModule","startModule","msgModule"})
public class XxxxApplication extends Application {
}
每個(gè)module中創(chuàng)建空java類(lèi)注解:
@Module("homeModule")
public class HomeModule{
}
組件間通信問(wèn)題:
不同組件Activity之間傳遞大量數(shù)據(jù)時(shí)可以通過(guò)EventBus來(lái)進(jìn)行傳遞,EventBus原理及用法:https://github.com/greenrobot/EventBus
編譯運(yùn)行
當(dāng)在gradle.properties中設(shè)置isDebug=true時(shí),可以獨(dú)立運(yùn)行每個(gè)module,獨(dú)立運(yùn)行調(diào)試,當(dāng)設(shè)置isDebug=false,可以編譯運(yùn)行整個(gè)project,注意isDebug變量設(shè)置改變時(shí),要重新對(duì)gradle進(jìn)行sync。
可能遇到的一些問(wèn)題:
1:如果遇到/com/github/mzule/activityrouter/router/RouterInit.java javaError:(7, 5) 錯(cuò)誤: 找不到符號(hào) 符號(hào):? 變量 RouterMapping等錯(cuò)誤,請(qǐng)檢查app是否把各個(gè)Module都依賴(lài)進(jìn)來(lái)了。
2:使用butterknife注解時(shí),每個(gè)Module會(huì)對(duì)應(yīng)生成R2文件,即使在base庫(kù)里注解過(guò)了,Module也要重新注解,組件中不能直接使用。
3:如果項(xiàng)目中使用到menu注意:
@Override
protected void onMenuItemClick(MenuItem item) {
//? ? ? ? switch (item.getItemId()) {
//? ? ? ? ? ? case R2.id.xxx:
//? ? ? ? ? ? ? ? Routers.open(mContext,"");
//? ? ? ? ? ? ? ? break;
//? ? ? ? }
if (item.getItemId() == R.id.xxx){
Routers.open(mContext,"");
}
super.onMenuItemClick(item);
}
尋找對(duì)應(yīng)的menu id時(shí),用if else 代替 switch,注:itemid 和 R2值不一樣,和R是一樣的。