使用ARouter進行Android模塊化開發

Android模塊化

關於爲何要進行Android模塊化開發,網上也已經講爛了,不過歸結起來,大致是能夠總結爲:在App開發的初期,代碼量不大,業務量比較少,一個App做爲一個單獨的模塊進行開發,每每問題不大。但隨着業務的增多,代碼變的愈來愈複雜,每一個模塊之間的代碼耦合變得愈來愈嚴重,結構愈來愈臃腫,修改一處代碼要編譯整個工程,致使很是耗時,這時候最好的辦法就是進行模塊化拆分。java

模塊化的好處

總結如今的模塊化,大致有如下一些好處:android

  • 公用功能,不用重複開發、修改,代碼複用性更強;
  • 獨立編譯運行,提升編譯速度,也就提升了開發效率;
  • 更利於團隊開發,不一樣的人能夠獨立負責不一樣的模塊;
  • 獨立模塊能夠採用不一樣的技術架構,嘗試新的技術方案,好比採用新的網絡框架,甚至換成Kotlin來開發App。

須要解決的問題

要將項目模塊化拆分,須要解決如下幾個問題:git

  • 模塊間頁面跳轉;
  • 模塊間事件通訊;
  • 模塊間服務調用;
  • 模塊的獨立運行;
  • 模塊間頁面跳轉路由攔截(如登陸)

對於上面的問題,均可以使用ARouter進行解決。github

ARouter框架

官方地址:ARouter開源地址 官方對ARouter框架的定義是:一個用於幫助 Android App 進行組件化改造的框架 —— 支持模塊間的路由、通訊、解耦。api

  • 支持直接解析標準URL進行跳轉,並自動注入參數到目標頁面中
  • 支持多模塊工程使用
  • 支持添加多個攔截器,自定義攔截順序
  • 支持依賴注入,可單獨做爲依賴注入框架使用
  • 支持InstantRun
  • 支持MultiDex(Google方案)
  • 映射關係按組分類、多級管理,按需初始化
  • 支持用戶指定全局降級與局部降級策略
  • 頁面、攔截器、服務等組件均自動註冊到框架
  • 支持多種方式配置轉場動畫
  • 支持獲取Fragment
  • 徹底支持Kotlin以及混編(配置見文末 其餘#5)
  • 支持第三方 App 加固(使用 arouter-register 實現自動註冊)
  • 支持生成路由文檔
  • 提供 IDE 插件便捷的關聯路徑和目標類

基本用法

添加依賴和配置

使用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 {
    ...
}
複製代碼

初始化SDK

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
複製代碼

ARouter Helper,

在 Android Studio 插件市場中搜索 ARouter Helper, 或者直接下載文檔上方 最新版本 中列出的 arouter-idea-plugin zip 安裝包手動安裝,安裝後 插件無任何設置,能夠在跳轉代碼的行首找到一個圖標 (navigation) 點擊該圖標,便可跳轉到標識了代碼中路徑的目標類。

在這裏插入圖片描述

ARouter模塊化示例

接下來,將會用一個demo介紹如何用ARouter進行模塊化開發,demo模塊化的總體架構以下圖所示。

在這裏插入圖片描述
每一個模塊的做用以下:

  • app:項目的宿主模塊,僅僅是一個空殼,依賴於其餘模塊,成爲項目架構的入口;

  • baselibrary:項目的基類庫,每一個子模塊都依賴共享公用的類和資源,防止公用的功能在不一樣的模塊中有多個實現方式;

  • module_route:集中管理全部模塊的route的庫;

  • module_main:閃屏頁,登陸頁,主頁等;

  • module_home:首頁模塊;

  • module_video:視頻模塊;

  • module_mine:個人模塊;

依賴模式與獨立模式的切換

使用模塊化開發的一個好處是,各個獨立的模塊能夠同時開發,獨立運行而沒必要依賴於宿主app,也就是每一個module是一個獨立的App,項目發佈的時候依賴到宿主App中便可。各業務模塊之間不容許存在相互依賴關係,可是須要依賴基類庫。 而且,單一模塊生成的apk體積也小,編譯時間也快,開發效率會高不少,同時也能夠獨立測試,要實現這樣的效果須要對項目作一些配置。

gradle.properties配置

在主項目的gradle.properties中須要設置一個開關,用來控制module的編譯模式,例如:

isModule=false
複製代碼

當isModule爲false時做爲依賴庫,只能以宿主app啓動項目,選擇運行模塊時其餘module前都是紅色的X,表示沒法運行。

在這裏插入圖片描述

當isModule爲true時,做爲單獨的模塊進行運行,選擇其中一個具體的module就能夠直接運行。

在這裏插入圖片描述

module清單文件

爲了完成依賴模式與獨立模式的切換,module清單文件須要配置兩個,一個做爲獨立項目的清單文件,一個做爲庫的清單文件,以module_main模塊爲例。

在這裏插入圖片描述
buildApp做爲依賴庫的清單文件,和獨立項目的清單文件buildModule區別是依賴庫的清單文件Application中沒有配置入口的Activity,其餘都同樣。

gradle配置

爲了完成切換,還須要對module的build.gradle文件進行配置,以下圖:

在這裏插入圖片描述

宿主app配置

接下來,在宿主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 Helper

常見問題

問題1

錯誤: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() ]
            }
        }
}

複製代碼

問題2

ARouter.getInstance().inject(this); 問題描述:有一個singletask啓動模式的activity,在onNewIntent方法中調用ARouter.getInstance().inject(this);得不到參數,查看ARouter在build過程當中生成的代碼能夠知道它是調用了activity的getIntent來獲取參數的,可是onNewIntent中的intent和在onCreate方法中的intent並不相同,因此須要在onNewIntent方法中調用setIntent方法,而後就能獲得參數了。

問題3

ARouter there's no route matched

不一樣module的一級路徑必須不一樣,不然會致使一個moudle中的一級路徑失效。

附:示例下載地址

相關文章
相關標籤/搜索