元件化架構
元件化和插件化的目的都是為了解決項目越來越複雜,耦合性高,牽一發而動全身,一個小的改動也要編譯十幾分鐘等問題,兩者的差別簡單來說元件化是在編譯期分子產品,插件化是在運作期。一般插件化用于動态修複bug或者動态更新子產品,相對來說黑科技更多一些,而相對于插件化,元件化的架構更容易操作,效率高,基于安卓自有特性和gradle的功能,沒有插件化那麼多的坑,對于大多數應用而言,其優勢還是相當明顯的。
先看下我們的架構圖:
App控制中心主要負責元件的添加和删除,路由規則的定義。
module是我們單獨開發的子產品,如個人中心,詳情頁,專題頁等等
common主要功能就是集合第三方的library,統一引入到項目中
原理與思路:
為每一個module設定library和application兩種屬性,通過配置檔案控制,當集合一起編譯時作為library依賴到app控制中心,當獨立開發時切換到application屬性變成一個普通的module,common作為一個公共的三方庫集合,頁面跳轉基于ARouter路由架構,消息傳遞用可以用EventBus,當然也可以用Arouter内部的API。
架構概覽:
其中main、modulefirst和modulesecond是三個獨立的子產品,應用的首頁在main裡,當然也可以指定到其他元件,隻需要配一個注解就可以,修改起來非常友善。
當為集合編譯時項目是這樣的:
當為獨立開發時項目是這樣的:
開始搭建
1.建立完工程後,配置可切換library和application屬性的檔案。
在project根節點下在gradle.properties檔案添加以下代碼:
# 每次更改“isModule”的值後,需要點選 "Sync Project" 按鈕
isModule=false
然後在每個元件的build.gradle根節點裡添加代碼:
if (isModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
2.清單檔案的處理
由于每一個元件都是一個獨立的APP,都有自己的清單檔案,都有自己的Application屬性和MainActivity,當合并一起編譯時勢必會和其他元件的清單檔案産生沖突,而我們自己的子產品又需要自己開發時用到清單檔案,為此,我們的解決方法是:分别建立一個debug檔案夾,一個release檔案夾,分别放置一個清單檔案,不同的工程屬性時啟用對應的清單檔案即可解決,兩個清單檔案的差別如圖所示:
然後再build.gradle裡添加如下代碼:
android {
/……/
//這裡是我們添加的代碼
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
//release模式下排除debug檔案夾中的所有Java檔案
java {
exclude 'debug/**'
}
}
}
}
}
3.解決全局Application群組件自己的Application的沖突問題
應用啟動時,系統會為每一個應用建立唯一一個Application對象,其生命周期最長一直到應用結束,我們開發時往往會自己定義一個Application,做一些初始化的操作,這時就要去告訴系統要執行個體化自己定義的,也就是我們在清單檔案的Application節點配置的name屬性,那麼我們的元件本就是獨立的APP,肯定會有自己的Application,如何合并編譯,肯定又有問題了,對此,我們的的解決方法是,先建立一個Common庫,這個庫包含了各種公共的類,如BaseActivity,BaseApplication,Utils等等,每一個元件的Application都繼承自Common的BaseApplication,這樣元件就可以用自己的Application了,記得在自己的清單檔案中做相應修改。為了保證合并編譯時隻有一個BaseApplication,我們可以這樣修改
然後在build.gradle裡的這一行代碼就起作用了:
4.對編譯版本統一配置,依賴庫也統一配置
這樣做的目的是為了統一元件的工作環境,避免API版本參差不齊帶來的問題,同時也符合規範化管理的要求,而且便于維護,預設情況下,如果是 aar 依賴,gradle 會自動幫我們找出新版本的庫而抛棄舊版本的重複依賴。但是如果你使用的是 project 依賴,gradle 并不會去去重,最後打包就會出現代碼中有重複的類了。為了避免同一個庫依賴兩次,我們把所有第三方依賴放到Common庫中管理,元件的build.gradle裡隻需要這樣寫:
5.對App控制中心子產品的處理
App子產品在項目裡負責路由規則定義群組件注冊,沒有界面,雖然看起來和普通module一樣,但是千萬不要搞混了,它除了管理功能,還有就是作為整個項目合并編譯的端口,通常我們debug編譯都是習慣這樣
這裡app就是這樣一個作用,輕按兩下即可合并所有元件一起編譯,在此雄偉的壯舉成功之前,我們一定要注意先修改App子產品的build.gradle檔案如下:
代碼貼出來
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
if (!isModule.toBoolean()) {
compile project(':main')
compile project(':modelfirst')
compile project(':modelsecond')
} else {
compile project(':common')
}
}
順便也把全局編譯版本統一配置:
在project的build.gradle裡這樣寫
ext{
// Sdk and tools
buildToolsVersion = localBuildToolsVersion
compileSdkVersion =
minSdkVersion =
targetSdkVersion =
versionCode =
versionName = "1.0"
javaVersion = JavaVersion.VERSION_1_8
aptCompilerVersion = "1.1.7"
routerVersion = "1.2.2"
loggerVersion = "1.15"
}
元件的build.gradle裡這樣寫
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
/……/
}
6.最後就是各個元件之間的跳轉問題也是最關心的問題。
這一部分,對于不熟悉Router的我真是踩了不少坑,其實總結起來卻是非常簡單,隻是一些小的細節沒有注意,你的APP就總是無法跳轉成功。先說項目如何配置:
本文章用的是github一個開源路由架構:ActivityRouter裡面有詳細的說明,另外阿裡也開源了一個路由架構:ARouter,有時間的化可以拿過來研究一下,使用起來都比較容易上手的,如果你想自己實作一個路由,可以參考這篇文章:Android路由實作
在project的build.gradle添加代碼:
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
//這是我們要添加的
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
然後在每一個元件的build.gradle裡添加:
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
apt 'com.github.mzule.activityrouter:compiler:1.1.7'
compile project(':common')
}
如圖所示:
sync工程一下後,開始處理路由配置
首先是App子產品,這個是編譯入口,需要管理所有元件,
建立一個類檔案
注意圖中的注解,是@Module,不是@Modules,
然後給MainApplication添加注解,這裡注意是@Modules了,如圖:
接下來處理應用入口的元件,注意APP隻是編譯控制元件,應用的首頁是由另一個元件控制的,這裡我定義為main元件,這個地方需要注意,和其他子產品略有不同,如圖:
注意看,這個Activity是沒有注解的,同時,其清單檔案要添加Launcher屬性。
對應的定義一個Main類,如圖
和入口元件不同的是,其他元件的Activity上要加注解:
這裡注意,注解裡的字段一定是群組件module的名稱是一緻的!
接下來就可以開始跳轉了,随意定義幾個按鈕,然後添加監聽裡的方法
當然路由協定有多種跳轉規則,後期我會将其他示例逐漸加到架構裡。
關于元件間的通信
元件内跳轉建議還是采用startActivity,組建間跳轉,可以用ActivityRouter的路由協定:
例如:
元件2定義了兩個Activity:
@Router("modelsecond")
public class ModelSecondActivity extends BaseActivity{……}
……
……
@Router("modelsecond/:demo")//注意這裡“/:demo”即作為此Activity的定位符,路由可以據此找到對應Activity
public class ActivityDemo extends BaseActivity{……}
元件1中有一個Activity:
@Router("modelfirst")
public class ModelFirstActivity extends BaseActivity{}
現在如果想從元件1的ModelFirstActivity 跳轉到元件2的ActivityDemo ,那麼點選事件裡隻需要這樣寫:
如果需要傳遞intent參數,那麼隻需要這麼寫:
在需要擷取參數的地方這麼寫:
getIntent().getStringExtra("sign");
getIntent().getStringExtra("name");
更多細節可以參考這裡:【ActivityRouter】
如果單純的傳遞消息可以用EventBus
注意事項
- 每一個元件,要給自己的所有資源檔案制定命名規則,避免和其他元件資源重名,切記
- 注意入口元件和其他元件的差別是入口Activity是沒有注解的
- App控制中心元件也就是編譯元件裡,@Module和@Modules切記不要記混了
- 總之就是細心,再細心,一定要自己動手搞一遍
最後貼出demo位址:【傳送門】
參考文章:
- http://blog.csdn.net/guiying712/article/details/55213884