Markdown版本筆記 | 個人GitHub首頁 | 個人博客 | 個人微信 | 個人郵箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
ARouter 路由 組件 跳轉 MD
***
目錄
===android
一個用於幫助 Android App 進行組件化改造
的框架 —— 支持模塊間的路由、通訊、解耦
git
模塊 | arouter-api | arouter-compiler | arouter-register | arouter-idea-plugin |
---|---|---|---|---|
2018-12-15 最新版本 |
標準URL
進行跳轉,並自動注入參數
到目標頁面中多模塊
工程使用攔截器
,自定義攔截順序依賴注入
,可單獨做爲依賴注入框架使用InstantRun
MultiDex
按組分類、多級管理,按需初始化
全局降級與局部降級
策略自動註冊
到框架轉場動畫
Fragment
Kotlin
以及混編第三方 App 加固
(使用 arouter-register 實現自動註冊)路由文檔
IDE 插件
便捷的關聯路徑和目標類外部URL
映射到內部頁面,以及參數傳遞與解析跨模塊
頁面跳轉,模塊間解耦攔截
跳轉過程,處理登錄、埋點等邏輯跨模塊API調用
,經過控制反轉來作組件解耦一、添加依賴和配置編程
android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } } } dependencies { api 'com.alibaba:arouter-api:x.x.x' // 須要注意的是api annotationProcessor 'com.alibaba:arouter-compiler:x.x.x' // 要與compiler匹配使用 }
二、添加註解json
// 在支持路由的頁面上添加註解(必選),這裏的路徑須要注意的是至少須要有兩級,/xx/xx @Route(path = "/test/activity") public class YourActivity extend Activity { ... }
三、初始化SDKapi
if (isDebug()) { ARouter.openLog(); // 打印日誌,這兩行必須寫在init以前,不然這些配置在init過程當中將無效 ARouter.openDebug(); // 開啓調試模式(若是在InstantRun模式下運行,必須開啓調試模式!線上版本須要關閉,不然有安全風險) } ARouter.init(mApplication);
四、發起路由操做緩存
ARouter.getInstance().build("/test/activity").navigation(); // 應用內簡單的跳轉 ARouter.getInstance().build("/test/1") .withLong("key1", 666L) // 跳轉並攜帶參數 .withString("key3", "888") .withObject("key4", new Test("Jack", "Rose")) .navigation();
五、添加混淆規則安全
-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
六、使用 Gradle 插件實現路由表的自動加載(可選)微信
apply plugin: 'com.alibaba.arouter' buildscript { repositories { jcenter() } dependencies { classpath "com.alibaba:arouter-register:?" } }
可選使用,經過 ARouter 提供的註冊插件進行路由表的自動加載(power by AutoRegister),默認經過掃描 dex 的方式進行加載,經過 gradle 插件進行自動註冊能夠縮短初始化時間,解決應用加固致使沒法直接訪問 dex 文件,初始化失敗的問題。須要注意的是,該插件必須搭配 api 1.3.0 以上版本使用!
七、使用 IDE 插件導航到目標類
在 Android Studio 插件市場中搜索 ARouter Helper
, 或者直接下載文檔上方 最新版本
中列出的 arouter-idea-plugin
zip 安裝包手動安裝,安裝後,插件無任何設置,能夠在跳轉代碼的行首找到一個圖標,點擊該圖標,便可跳轉到標識了代碼中路徑的目標類。
一、經過URL跳轉
新建一個Activity用於監聽Schame事件,以後直接把url傳遞給ARouter便可
public class SchameFilterActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Uri uri = getIntent().getData(); ARouter.getInstance().build(uri).navigation(); finish(); } }
AndroidManifest.xml 中的配置
<activity android:name=".activity.SchameFilterActivity"> <!-- Schame --> <intent-filter> <data android:host="m.aliyun.com" android:scheme="arouter"/> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> </intent-filter> </activity>
二、解析URL中的參數
URL中不能傳遞Parcelable類型數據,經過ARouter api能夠傳遞Parcelable對象
@Route(path = "/test/activity") public class Test1Activity extends Activity { @Autowired public String name; // 爲每個參數聲明一個字段,並使用 @Autowired 標註 @Autowired int age; @Autowired(name = "girl") boolean boy; // 經過name來映射URL中的不一樣參數 @Autowired TestObj obj; // 支持解析自定義對象,URL中使用json傳遞 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ARouter.getInstance().inject(this); //注入 Log.d("param", name + age + boy); // ARouter會自動對字段進行賦值,無需主動獲取 } }
若是須要傳遞自定義對象
,新建一個類(並不是自定義對象類),而後實現 SerializationService
,並使用@Route
註解標註(方便用戶自行選擇序列化方式),例如:
@Route(path = "/yourservicegroupname/json") public class JsonServiceImpl implements SerializationService { @Override public void init(Context context) { //可選,用於對序列化框架初始化 } @Override public <T> T json2Object(String text, Class<T> clazz) { return JSON.parseObject(text, clazz); //自行選擇反序列化方式,好比Gson、fastjson } @Override public String object2Json(Object instance) { return JSON.toJSONString(instance); //自行選擇序列化方式,好比Gson、fastjson } }
三、聲明攔截器
攔截跳轉過程,面向切面編程
。
比較經典的應用就是在跳轉過程當中處理登錄事件
,這樣就不須要在目標頁重複作登錄檢查
。
攔截器會在跳轉之間
執行,多個攔截器會按優先級順序依次執行。
@Interceptor(priority = 8, name = "測試用攔截器") public class TestInterceptor implements IInterceptor { @Override public void process(Postcard postcard, InterceptorCallback callback) { //...條件判斷 callback.onContinue(postcard); // 處理完成,交還控制權 // callback.onInterrupt(new RuntimeException("我以爲有點異常")); // 以爲有問題,中斷路由流程 // 以上兩種至少須要調用其中一種,不然不會繼續路由 } @Override public void init(Context context) { // 攔截器的初始化,會在sdk初始化的時候調用該方法,僅會調用一次 } }
四、處理跳轉結果
使用兩個參數的navigation方法,能夠獲取單次跳轉的結果。
ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() { @Override public void onFound(Postcard postcard) { //... } @Override public void onLost(Postcard postcard) { //... } });
五、自定義全局降級策略
實現DegradeService接口,並加上一個Path內容任意的註解便可
@Route(path = "/xxx/xxx") public class DegradeServiceImpl implements DegradeService { @Override public void onLost(Context context, Postcard postcard) { // do something. } @Override public void init(Context context) { } }
六、爲目標頁面聲明更多信息
咱們常常須要在目標頁面中配置一些屬性,比方說"是否須要登錄"之類的,能夠經過 Route 註解中的 extras
屬性進行擴展。
這個屬性是一個 int 值,也就是32位,能夠配置32個開關。
剩下的能夠自行發揮,經過字節操做能夠標識32個開關,經過開關標記目標頁面的一些屬性,在攔截器中能夠拿到這個標記進行業務邏輯判斷
@Route(path = "/test/activity", extras = Consts.XXXX)
七、經過依賴注入
解耦
服務管理(一) 暴露服務
public interface HelloService extends IProvider { String sayHello(String name); // 聲明接口,其餘組件經過接口來調用服務 }
實現接口
@Route(path = "/yourservicegroupname/hello", name = "測試服務") public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "hello, " + name; } @Override public void init(Context context) { } }
服務管理(二) 發現服務
public class Test { @Autowired HelloService helloService; @Autowired(name = "/yourservicegroupname/hello") HelloService helloService2; HelloService helloService3; HelloService helloService4; public Test() { ARouter.getInstance().inject(this); } public void testService() { // 一、(推薦)使用依賴注入的方式發現服務,經過註解標註字段便可使用,無需主動獲取 // Autowired註解中標註name以後,將會使用byName的方式注入對應的字段,不設置name屬性,會默認使用byType的方式發現服務(當同一接口有多個實現的時候,必須使用byName的方式發現服務) helloService.sayHello("Vergil"); helloService2.sayHello("Vergil"); // 二、使用依賴查找的方式發現服務,主動去發現服務並使用,下面兩種方式分別是byName和byType helloService3 = ARouter.getInstance().navigation(HelloService.class); helloService4 = (HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation(); helloService3.sayHello("Vergil"); helloService4.sayHello("Vergil"); } }
一、初始化中的其餘設置
ARouter.openLog(); // 開啓日誌 ARouter.openDebug(); // 使用InstantRun的時候,須要打開該開關,上線以後關閉,不然有安全風險 ARouter.printStackTrace(); // 打印日誌的時候打印線程堆棧
二、詳細的API說明
ARouter.getInstance().build("/home/main").navigation(); // 構建標準的路由請求 ARouter.getInstance().build("/home/main", "ap").navigation(); // 構建標準的路由請求,並指定分組 ARouter.getInstance().build(uri).navigation(); // 構建標準的路由請求,經過Uri直接解析 ARouter.getInstance().build("/home/main", "ap").navigation(this, 5); // startActivityForResult 形式跳轉 ARouter.getInstance().build("/home/main").with(params).navigation(); // 直接傳遞Bundle ARouter.getInstance().build("/home/main").withFlags().navigation(); // 指定Flag ARouter.getInstance().withObject("key", new TestObj("Jack", "Rose")).navigation(); // 對象傳遞 ARouter.getInstance().build("/home/main").getExtra(); // 以爲接口不夠多,能夠直接拿出Bundle賦值 ARouter.getInstance().build("/home/main").greenChannel().navigation();// 使用綠色通道(跳過全部的攔截器) ARouter.setLogger();// 使用本身的日誌工具打印日誌 ARouter.setExecutor();// 使用本身提供的線程池 Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation(); //獲取Fragment ARouter.getInstance().build("/test/activity2") .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom).navigation(this); //轉場動畫 ARouter.getInstance().build("/test/activity2") .withOptionsCompat(compat).navigation(this); // 轉場動畫(API16+)
三、獲取原始的URI
String uriStr = getIntent().getStringExtra(ARouter.RAW_URI);
四、重寫跳轉URL
實現 PathReplaceService 接口,並加上一個 Path 內容任意的註解便可
@Route(path = "/xxx/xxx") // 必須標明註解 public class PathReplaceServiceImpl implements PathReplaceService { /** * For normal path. * * @param path raw path */ String forString(String path) { return path; // 按照必定的規則處理以後返回處理後的結果 } /** * For uri type. * * @param uri raw uri */ Uri forUri(Uri uri) { return url; // 按照必定的規則處理以後返回處理後的結果 } }
五、生成路由文檔
生成的文檔路徑:build/generated/source/apt/(debug or release)/com/alibaba/android/arouter/docs/arouter-map-of-${moduleName}.json
android { defaultConfig { javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable"] } } } }
一、路由中的分組概念
該分組纔會被初始化
@Route
註解主動指定分組,不然使用路徑中第一段字符串/*/
做爲分組ARouter.getInstance().build(path, group)
進行跳轉,手動指定分組,不然沒法找到@Route(path = "/test/1", group = "app")
二、攔截器和服務的異同
init(Context)
方法,可是二者的調用時機不一樣等待
,直到初始化完成。三、Kotlin項目中的配置方式
能夠參考 module-kotlin 模塊中的寫法
apply plugin: 'kotlin-kapt' kapt { arguments { arg("AROUTER_MODULE_NAME", project.getName()) } } dependencies { compile 'com.alibaba:arouter-api:x.x.x' kapt 'com.alibaba:arouter-compiler:x.x.x' }
一、"W/ARouter::: ARouter::No postcard[ ]"
二、"W/ARouter::: ARouter::There is no route match the path [/xxx/xxx], in group [xxx][ ]"
三、開啓InstantRun以後沒法跳轉(高版本Gradle插件下沒法跳轉)?
由於開啓InstantRun以後,不少類文件不會放在本來的dex中,須要單獨去加載,ARouter默認不會去加載這些文件,由於安全緣由,只有在開啓了openDebug以後,ARouter纔回去加載InstantRun產生的文件,因此在以上的狀況下,須要在init以前調用openDebug。
四、TransformException:java.util.zip.ZipException: duplicate entry ....
ARouter有按組加載的機制,ARouter容許一個module中存在多個分組,可是不容許多個module中存在相同的分組,會致使映射文件衝突。
五、Kotlin類中的字段沒法注入如何解決?
首先,Kotlin中的字段是能夠自動注入的,可是注入代碼爲了減小反射,使用的字段賦值的方式來注入的,Kotlin默認會生成set/get方法,並把屬性設置爲private,因此只要保證Kotlin中字段可見性不是private便可,簡單解決能夠在字段上添加 @JvmField
。
六、經過URL跳轉以後,在intent中拿不到參數如何解決?
須要注意的是,若是不使用自動注入,那麼能夠不寫 ARouter.getInstance().inject(this)
,可是須要取值的字段仍然須要標上 @Autowired
註解,由於只有標上註解以後,ARouter才能知道以哪種數據類型提取URL中的參數並放入Intent中,這樣您才能在intent中獲取到對應的參數。
七、新增頁面以後,沒法跳轉?
ARouter加載Dex中的映射文件會有必定耗時,因此ARouter會緩存映射文件,直到新版本升級(版本號或者versionCode變化),而若是是開發版本,ARouter 每次啓動都會從新加載映射文件,開發階段必定要打開 Debug 功能。
2018-12-15