關於爲何要進行Android模塊化開發,網上也已經講爛了,不過歸結起來,大致是能夠總結爲:在App開發的初期,代碼量不大,業務量比較少,一個App做爲一個單獨的模塊進行開發,每每問題不大。但隨着業務的增多,代碼變的愈來愈複雜,每一個模塊之間的代碼耦合變得愈來愈嚴重,結構愈來愈臃腫,修改一處代碼要編譯整個工程,致使很是耗時,這時候最好的辦法就是進行模塊化拆分。java
總結如今的模塊化,大致有如下一些好處:android
要將項目模塊化拆分,須要解決如下幾個問題:git
對於上面的問題,均可以使用ARouter進行解決。github
官方地址:ARouter開源地址 官方對ARouter框架的定義是:一個用於幫助 Android App 進行組件化改造的框架 —— 支持模塊間的路由、通訊、解耦。api
使用ARouter以前,須要先添加相應的依賴,依賴的腳步以下:安全
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}
}
dependencies {
// 替換成最新版本, 須要注意的是api
// 要與compiler匹配使用,均使用最新版能夠保證兼容
compile 'com.alibaba:arouter-api:x.x.x'
annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
...
}
// 舊版本gradle插件(< 2.2),可使用apt插件,配置方法見文末'其餘#4'
// Kotlin配置參考文末'其餘#5'
複製代碼
要想ARouter識別路由,須要使用@Route註解標示具體的路徑。例如:bash
// 在支持路由的頁面上添加註解(必選)
// 這裏的路徑須要注意的是至少須要有兩級,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
...
}
複製代碼
if (isDebug()) { // 這兩行必須寫在init以前,不然這些配置在init過程當中將無效
ARouter.openLog(); // 打印日誌
ARouter.openDebug(); // 開啓調試模式(若是在InstantRun模式下運行,必須開啓調試模式!線上版本須要關閉,不然有安全風險)
}
ARouter.init(mApplication); // 儘量早,推薦在Application中初始化
複製代碼
所謂發起路由操做,就是指觸發路由的操做,例如:網絡
// 1. 應用內簡單的跳轉(經過URL跳轉在'進階用法'中)
ARouter.getInstance().build("/test/activity").navigation();
// 2. 跳轉並攜帶參數
ARouter.getInstance().build("/test/1")
.withLong("key1", 666L)
.withString("key3", "888")
.withObject("key4", new Test("Jack", "Rose"))
.navigation();
複製代碼
若是要接受傳遞處理的數據,可使用下面的方式:架構
@Route(path = MainRoutePath.MAIN_ACTIVITY)
public class MainActivity extends BaseActivity {
/**
* 接收參數
*/
@Autowired(name = "name")
public String name;
@Autowired(name = "age")
public int age;
...
}
複製代碼
// A more classic application is to handle login events during a jump so that there is no need to repeat the login check on the target page.
// Interceptors will be executed between jumps, multiple interceptors will be executed in order of priority
@Interceptor(priority = 8, name = "test interceptor")
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
...
// No problem! hand over control to the framework
callback.onContinue(postcard);
// Interrupt routing process
// callback.onInterrupt(new RuntimeException("Something exception"));
// The above two types need to call at least one of them, otherwise it will not continue routing
}
@Override
public void init(Context context) {
// Interceptor initialization, this method will be called when sdk is initialized, it will only be called once
}
}
複製代碼
ARouter提供的降級策略主要有兩種方式,一種是經過回調的方式;一種是提供服務接口的方式。 1、回調方式 這種方式在跳轉失敗的時候會回調NavCallback接口的onLost方法。ARouter提供的回調方式的函數以下:app
ARouter.getInstance().build(MainRoutePath.MAIN_ACTIVITY).navigation(this, new NavCallback() {
@Override
public void onFound(Postcard postcard) {
Log.d("ARouter", "找到了");
}
@Override
public void onLost(Postcard postcard) {
Log.d("ARouter", "找不到了");
}
@Override
public void onArrival(Postcard postcard) {
Log.d("ARouter", "跳轉完了");
}
@Override
public void onInterrupt(Postcard postcard) {
Log.d("ARouter", "被攔截了");
}
});
複製代碼
2、服務接口 全局降級-服務接口的方式主要處理邏輯在內部,暴露的接口很友好。
ARouter.getInstance().build("/test/test").navigation();
複製代碼
此種降級策略須要實現服務接口DegradeService,返回的就一個方法就是onLost。例如:
@Route(path = RoutePath.DEGRADE)
public class DegradeServiceImpl implements DegradeService {
@Override
public void onLost(Context context, Postcard postcard) {
ARouter.getInstance().build(RoutePath.DEGRADE_TIP).greenChannel().navigation();
}
@Override
public void init(Context context) {
}
}
複製代碼
爲了不打包時出現錯誤,須要將下面的內容使用keep標示。
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep public class com.alibaba.android.arouter.facade.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 若是使用了 byType 的方式獲取 Service,需添加下面規則,保護接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 若是使用了 單類注入,即不定義接口實現 IProvider,需添加下面規則,保護實現
# -keep class * implements com.alibaba.android.arouter.facade.template.IProvider
複製代碼
在 Android Studio 插件市場中搜索 ARouter Helper, 或者直接下載文檔上方 最新版本 中列出的 arouter-idea-plugin zip 安裝包手動安裝,安裝後 插件無任何設置,能夠在跳轉代碼的行首找到一個圖標 (navigation) 點擊該圖標,便可跳轉到標識了代碼中路徑的目標類。
接下來,將會用一個demo介紹如何用ARouter進行模塊化開發,demo模塊化的總體架構以下圖所示。
每一個模塊的做用以下:app:項目的宿主模塊,僅僅是一個空殼,依賴於其餘模塊,成爲項目架構的入口;
baselibrary:項目的基類庫,每一個子模塊都依賴共享公用的類和資源,防止公用的功能在不一樣的模塊中有多個實現方式;
module_route:集中管理全部模塊的route的庫;
module_main:閃屏頁,登陸頁,主頁等;
module_home:首頁模塊;
module_video:視頻模塊;
module_mine:個人模塊;
使用模塊化開發的一個好處是,各個獨立的模塊能夠同時開發,獨立運行而沒必要依賴於宿主app,也就是每一個module是一個獨立的App,項目發佈的時候依賴到宿主App中便可。各業務模塊之間不容許存在相互依賴關係,可是須要依賴基類庫。 而且,單一模塊生成的apk體積也小,編譯時間也快,開發效率會高不少,同時也能夠獨立測試,要實現這樣的效果須要對項目作一些配置。
在主項目的gradle.properties中須要設置一個開關,用來控制module的編譯模式,例如:
isModule=false
複製代碼
當isModule爲false時做爲依賴庫,只能以宿主app啓動項目,選擇運行模塊時其餘module前都是紅色的X,表示沒法運行。
當isModule爲true時,做爲單獨的模塊進行運行,選擇其中一個具體的module就能夠直接運行。
爲了完成依賴模式與獨立模式的切換,module清單文件須要配置兩個,一個做爲獨立項目的清單文件,一個做爲庫的清單文件,以module_main模塊爲例。
buildApp做爲依賴庫的清單文件,和獨立項目的清單文件buildModule區別是依賴庫的清單文件Application中沒有配置入口的Activity,其餘都同樣。爲了完成切換,還須要對module的build.gradle文件進行配置,以下圖:
接下來,在宿主app的build.gradle中添加模塊依賴,以下所示:
dependencies {
if (!isModule.toBoolean()) {
implementation project(':module_home')
implementation project(':module_video')
implementation project(':module_main')
implementation project(':module_mine')
implementation project(':module_router')
}
}
複製代碼
錯誤:ARouter::Compiler >>> No module name, for more information, look at gradle log. 檢查項目依賴的所有module,包括module依賴的module,爲了可以進行單獨的編譯,因此須要爲每個module添加名稱,即在每一個module的 build.gradle中加上下面的代碼:
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [ AROUTER_MODULE_NAME : project.getName() ]
}
}
}
複製代碼
ARouter.getInstance().inject(this); 問題描述:有一個singletask啓動模式的activity,在onNewIntent方法中調用ARouter.getInstance().inject(this);得不到參數,查看ARouter在build過程當中生成的代碼能夠知道它是調用了activity的getIntent來獲取參數的,可是onNewIntent中的intent和在onCreate方法中的intent並不相同,因此須要在onNewIntent方法中調用setIntent方法,而後就能獲得參數了。
ARouter there's no route matched
不一樣module的一級路徑必須不一樣,不然會致使一個moudle中的一級路徑失效。
附:示例下載地址