歡迎star/issue,項目地址:github.com/Dovar66/DRo…java
組件化技術適用於須要多人協做的中大型項目,若是是一我的的項目且開發人員未實踐過組件化方案則不建議採用。android
demo下載git
DRouter主要提供三大功能:界面路由、動做路由和事件總線,幫助Android開發者更容易地完成項目的組件化改造。
特別是對於多進程應用,引入DRouter可以讓開發者在不用瞭解AIDL的狀況下就能夠進行跨進程通訊.
複製代碼
* 完美支持多進程,且不須要使用者去bindService或自定義AIDL.
* 頁面路由:支持給Activity定義url,而後經過url跳轉到Activity,支持添加攔截器.
* 支持跨進程的API調用(動做路由).
* 支持跨進程的事件總線.
* 基於AOP引導Module的初始化以及頁面、攔截器、Provider的自動註冊.
複製代碼
1.在項目根目錄的 build.gradle 中添加 JitPack 倉庫:github
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
複製代碼
2.在BaseModule中添加依賴:api
api 'com.github.Dovar66.DRouter:router-api:1.0.8'
複製代碼
3.在其餘須要用到DRouter的組件中添加註解處理器的依賴:網絡
annotationProcessor 'com.github.Dovar66.DRouter:router-compiler:1.0.8'
同時在這些組件的defaultConfig中配置註解參數,指定惟一的組件名:
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName()]
}
}
}
複製代碼
4.多進程配置:架構
* 若是你的項目須要使用多進程廣域路由,那麼請讓你的Application實現 IMultiProcess 接口,廣域路由默認是關閉狀態,只有實現了該接口才會啓用。
* 在App module的build.gradle文件中,且必須在apply plugin: 'com.android.application'以後引用編譯插件RouterPlugin,具體以下:
apply plugin: 'com.android.application'
apply plugin: "com.dovar.router.plugin" //必須在apply plugin: 'com.android.application'以後,不然找不到AppExtension
buildscript {
repositories {
google()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.RouterPlugin:plugin:2.0.0"
}
}
複製代碼
DRouter.init(app);
複製代碼
在組件中建立BaseAppInit的子類,並添加Module註解:
@Module
public class AInit extends BaseAppInit {
@Override
public void onCreate() {
super.onCreate();
//與Application.onCreate()的執行時機相同
//建議在這裏完成組件內的初始化工做
}
}
註解處理器會將AInit註冊到DRouter,當DRouter初始化時,會調用被註冊的BaseAppInit子類的onCreate().
BaseAppInit中提供了Application實例,用於組件工程中獲取全局的應用上下文.
複製代碼
添加Route註解,可經過interceptor設置攔截器:
@Route(path = "/b/main", interceptor = BInterceptor.class)
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.module_b_activity_main);
}
}
而後在項目中使用DRouter進行頁面跳轉:
DRouter.navigator("/b/main").navigateTo(mContext);
複製代碼
建立相應的AbsProvider子類並添加Provider註解,而後在類中註冊Action:
@Provider(key = "a")
public class AProvider extends AbsProvider {
@Override
protected void registerActions() {
registerAction("test1", new Action() {
@Override
public RouterResponse invoke(@NonNull Bundle params, Object extra) {
Toast.makeText(appContext, "彈個窗", Toast.LENGTH_SHORT).show();
return null;
}
});
registerAction("test2", new Action() {
@Override
public RouterResponse invoke(@NonNull Bundle params, Object extra) {
if (extra instanceof Context) {
Toast.makeText((Context) extra, params.getString("content"), Toast.LENGTH_SHORT).show();
}
return null;
}
});
}
}
接下來就能夠在項目中使用:
DRouter.router("a","test1").route();
DRouter.router("a","test2")
.withString("content","也彈個窗")
.extra(context)
.route();
//跨進程調用
DRouter.multiRouter("a","test1").route(process);
須要注意的是,跨進程調用時,目標Action將會在Binder線程中執行,能夠經過設置runOnUiThread指定Action在ui線程執行.
DRouter.multiRouter("a","test1").runOnUiThread().route(process);
複製代碼
有兩種訂閱方式:
1.生命週期感知,不須要手動取消訂閱:
DRouter.subscribe(this, ServiceKey.EVENT_A, new EventCallback() {
@Override
public void onEvent(Bundle e) {
Toast.makeText(MainActivity.this, "/b/main/收到事件A", Toast.LENGTH_SHORT).show();
}
});
2.須要手動取消訂閱:
Observer<Bundle> mObserver = DRouter.subscribeForever("event_a", new EventCallback() {
@Override
public void onEvent(Bundle e) {
Toast.makeText(MainActivity.this, "/b/main/收到事件A", Toast.LENGTH_SHORT).show();
}
});
複製代碼
Bundle bundle = new Bundle();
bundle.putString("content", "事件A");
DRouter.publish(ServiceKey.EVENT_A, bundle);
複製代碼
DRouter.unsubscribe("event_a", mObserver);
複製代碼
-keep class com.dovar.router.generate.** { *; }
複製代碼
支持給Activity定義path,而後經過path跳轉到Activity,可設置跳轉攔截器.
複製代碼
服務提供者向DRouter註冊Action實現對其餘組件和進程暴露服務。注意:跨進程調用時傳遞的參數須要實現序列化,不然會被DRouter過濾掉.
複製代碼
關於APP殼工程app
管理打包配置.
設置組件引用.
集中管理混淆規則,各個組件中再也不配置混淆文件.
複製代碼
關於應用組件層框架
業務中心,包含全部業務組件.
複製代碼
關於公共服務層
管理跨組件調用和公共資源,詳細可參考項目中的common_service.
爲何要在基礎框架層和應用組件層中間多架設一個公共服務層?
* 封裝對基礎框架層功能API的調用,方便應對往後更換第三方庫的需求,相信不少程序員都經歷過更換第三方庫(特別是基礎庫)的痛苦啦,
若是項目中沒有本身封裝而是直接引用第三方API的話,等到要換的時候就會發現須要修改的代碼實在太多了。
* 儲存公用資源和代碼,暴露給上層業務使用,同時避免這些資源被下沉到基礎框架層,從而減小對基礎框架層的非必要更新。
在多人協做項目中,基礎框架必須是穩定的,因此咱們但願有儘量少的commit指向基礎框架層。
複製代碼
關於基礎框架層
與業務無關的通用功能模塊,如網絡請求、圖片加載、通用的自定義控件等.
複製代碼
設置一個可運行的殼工程,如示例中的app.而後在殼工程中配置組件依賴,要單獨調試某個組件的時候將其餘組件依賴註釋掉便可.
複製代碼
每一個module都有一份本身的AndroidManifest清單文件,在APP的編譯過程當中最終會將全部module的清單文件合併成一份。
咱們能夠在配置爲Application的module下的build/intermediates/manifests路徑下找到合成後的AndroidManifest文件,對比編譯先後的差別就能大體分析出合併規則和衝突處理規則。
須要注意的是若是在多個module中出現同名資源(如 android:label="@string/app_name"),且同名資源被合成後的AndroidManifest.xml引用,則會優先取用當前ApplicationModule的資源。
libModule中R文件裏的id再也不是靜態常量,而是靜態變量,因此不能再使用switch..case..語法操做資源id
複製代碼
1. 防止出現同名資源,建議每一個module下的資源命名都增長惟一識別字符,如module-live中的都帶前綴"mlive_",mlive_icon_close.png
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 15
targetSdkVersion 27
...
}
resourcePrefix "module_a_" //能夠利用 resourcePrefix 限定資源命名前綴
}
2. 關於資源的拆分,一些style、常見的string、共用的圖片、drawable等資源,建議存放在common_service當中。對於屬於不一樣模塊的資源則應該存放在各自的module中。
複製代碼
Note:你依然能夠沿用現有項目的版本管理方案,可跳過此部份內容.
複製代碼
通常咱們項目只會對應於一個Git倉庫,因而全部開發成員均可以對項目中全部代碼進行編輯並提交修改,但做爲項目管理者,咱們想讓成員只能提交本身負責的業務代碼,避免成員在開發過程當中不當心修改了其餘成員的代碼致使出現bug。而經過組件化後,咱們就能夠根據成員開發職責從新設置代碼修改權限啦。
假設:在開發過程當中基礎框架層不變,甲負責module_a,乙負責module_b,丙負責module_c和打包,甲乙丙均可以修改common_service。因而咱們將module_a/module_b/module_c/common_service全都獨立成子倉庫,module_a倉庫只對甲開放修改權限,module_b倉庫只對乙開放修改權限,module_c倉庫只對丙開放修改權限,因而就有下圖所示的權限分佈:
有如下三種Git部署方式可供選擇:
* 主項目下直接部署多個子倉庫
直接在主項目下引入全部子倉庫.
優勢:不用學習新的Git命令.
缺點:下載主項目時操做較複雜,須要先clone主項目而後再在主項目下clone全部子項目.(能夠經過配置腳本完成一鍵clone).
* git submodule
關於submodule如何使用請自行百度.
優勢:使用比subtree簡單,也沒有第一種方式的Git clone問題.
缺點:submodule的方式不能將在主項目中對子項目的修改推送到子項目倉庫.
* git subtree
[如何使用](https://blog.csdn.net/Dovar_66/article/details/83185288)
優勢:能夠將在主項目中對子項目的修改推送到子項目倉庫.
缺點:Git命令使用較複雜,組員學習成本高.
複製代碼
我目前用的第一種方式。附一個AS插件,可能用得上:一鍵Git Pull項目下全部倉庫的當前分支
徹底的組件化拆分並不是一兩日就能完成,而咱們的項目卻總會不斷有新的需求等待開發,版本迭代工做幾乎註定了咱們不可能將項目需求暫停來作組件化。
那麼,版本迭代與組件化拆分就須要同步進行,下面是個人建議:
1.開始準備:
* 新增APP殼工程,建議參考本項目中的app工程.
* 將你項目當前的application工程做爲公共服務層(後面直接用common_service表示),固然,因爲還未開始拆分組件,因此此時它也是最大的業務組件.
* 新增一個組件(後面用module_search表示),建議優先選擇一個本身最熟悉或相對簡單的業務模塊着手,好比我本身公司項目的搜索模塊,它只有搜索功能且與其餘模塊交互不多,因此我選擇由它開始。
2.創建依賴鏈:
殼工程依賴common_service.
殼工程依賴module_search.
module_search依賴common_service.(implementation依賴)
3.引入DRouter:
參考上面的DRouter使用說明.
4.分離公共服務層與基礎架構層(非必須):
若是以前你的項目沒有分離業務層和基礎架構層,那麼建議你如今將基礎架構從common_service中抽離出來.
5.逐步拆分組件:(這個過程短則幾天,長則數月,項目越大耦合越重則耗時越長,建議徐徐推動)
拆分第一個組件:
* 前面咱們已經新增了module_search,因此如今要將搜索模塊的代碼從common_service中抽離並放入搜索組件,此時搜索組件依然能夠直接引用公共服務層的代碼,但公共服務層則只能經過路由使用搜索功能.
* 在開發主線作新需求時,新增的資源文件建議最好放到對應的組件工程中,以前的資源文件能夠暫時保留在公共服務層,等待後續由各個組件工程認領走,儘量少的積壓在公共服務層。
* 權限、Android四大組件、特有的第三方庫引用等都應該聲明在對應的組件Module中,而不該沉入公共服務層,更不容許進入基礎框架層。
(在第一個組件拆分紅功並推入市場後,若是反饋良好,那麼就能夠繼續拆分其餘的組件了)
拆分第二個組件、第三個...
組件拆分粒度取決於你的業務模塊和組員職責,請按需拆分。
複製代碼
個人其餘項目:同窗,你的系統Toast可能須要修復一下!