路由框架ARouter使用及原始碼解析(一)
系列文章:
一、什麼是路由?
路由是指路由器從一個介面上收到資料包,根據資料路由包的目的地址進行定向並轉發到另一個介面的過程。—百度百科
以Android為例,各個元件module可以看成一個個網路,而路由就可以看成是各個模組頁面跳轉的中轉站,除了中轉以外,路由還可以過濾或攔截一些不安全或不規範的跳轉。
二、阿里ARouter
官方定義:A framework for assisting in the renovation of Android componentization (幫助 Android App 進行元件化改造的路由框架)
其實Android的跳轉已經提供了Intent,Intent不僅可以顯示跳轉,也可以隱式跳轉。那麼ARouter為什麼還會存在呢?讓我們對比一下原生跳轉和路由跳轉:
1、原生顯示跳轉必須依賴於類,強耦合,而隱式跳轉需要都在AndroidManifest裡集中註冊,協作麻煩;而路由跳轉通過URL索引,低耦合,協作方便;
2、原生在通過staryActivity啟動跳轉後就交由系統控制,並不能做攔截;路由跳轉可以對跳轉做過濾或攔截。
通過對比,我們發現路由特別適合用來做跳轉(尤其是元件間的通訊及跳轉),下面就來看一下阿里ARouter的整合及使用吧~
2.1、配置&初始化
在app的build.config中配置:
compile 'com.alibaba:arouter-api:1.4.1' annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
在各個需要使用ARouter模組的build.gradle的defaultConfig配置中加入:
javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } }
注意:新版本已經改成AROUTER_MODULE_NAME 來獲取module名字了。
上面配置中,annotationProcessor用來宣告註解解析器,arouter-compiler用來解析ARouter中的各個註解(後面會講到),通過APT方式在編譯期間自動生成class類,關於annotationProcessor可以檢視下面這篇文章:
https://blog.csdn.net/xx326664162/article/details/68490059配置完成後,進行初始化:
在自定義Application中進行初始化:
if (BuildConfig.DEBUG) { // 列印日誌 ARouter.openLog(); // 開啟除錯模式(如果在InstantRun模式下執行,必須開啟除錯模式!線上版本需要關閉,否則有安全風險) ARouter.openDebug(); } // 儘可能早,推薦在Application中初始化 ARouter.init(this);
初始化完成後,就可以開始使用了~
2.1、基本跳轉
以Activity跳轉為例,比如從Activity1跳轉到Activity2,首先在1、目標Activity2中:
@Route(path = MConstant.ACTIVITY2) public class Activity2 extends Activity { }
Activity2添加註解@Route,path是跳轉路徑,一般都寫在統一的一個類中,方便維護:
public class MConstant { public static final String ACTIVITY2 = "/main/activity2"; public static final String TRANSFER_KEY = "transfer_key"; }
2、在Activity1中進行ARouter注入並實現跳轉:
public class Activity1 extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ARouter.getInstance().inject(this); findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ARouter.getInstance().build(MConstant.ACTIVITY2).navigation(); } }); }
上面就實現了簡單的頁面跳轉,如果想傳遞引數,可以用下面的方式:
ARouter.getInstance().build(path).withString(MConstant.TRANSFER_KEY,"value").navigation();
withXXX處填的是引數的key和value (如果ARouter傳遞的是物件,首先該物件需要Parcelable或者Serializable序列化) ,navigation發射了路由跳轉。在目標類中,通過註解@Autowired來獲取傳遞值:
public class Activity2 extends Activity { @Autowired(name = TRANSFER_KEY) public String qrText; }
2.3、獲取Fragment例項
首先在Fragment上使用註解@Route
@Route(path = "/test/fragment") public class BlankFragment extends Fragment { }
獲取Fragment例項:
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
通過上面的程式碼就可以獲取Fragment的例項,這在跨模組中使用Fragment是很有用的。
2.4、進階用法之攔截器&通過URL跳轉
攔截器:
@Interceptor(priority = 1) public class MyInterceptor implements IInterceptor { private Context context; @Override public void process(Postcard postcard, InterceptorCallback callback) { if (MConstant.ACTIVITY2.equals(postcard.getPath())) { //如果是跳轉Activity2,則攔截 callback.onInterrupt(null); } else { callback.onContinue(postcard); } } @Override public void init(Context context) { this.context = context; } }
攔截器需要實現IInterceptor並通過註解@Interceptor來宣告,其中多個攔截器的優先順序根據priority來判斷,值越小優先順序越高。
通過URL跳轉:
Uri testUriMix = Uri.parse("arouter://m.aliyun.com/main/activity2"); ARouter.getInstance().build(testUriMix) .withString("key1", "value1") .navigation();
跟上面介紹的普通跳轉幾乎一樣,上面是用的path跳轉,而這裡使用的是URL跳轉,一般在自定義協議(如webview)時,使用URL跳轉非常的方便,並且可以對URL做攔截、轉換等。
2.5、服務管理
比如ModuleA中想呼叫ModuleB中的方法,在公共引用庫中宣告介面並繼承IProvider:
public interface IModuleService extends IProvider { String getModuleName(); }
在ModuleB中定義介面實現類:
@Route(path = MConstant.MODULE_SERVICE) public class ChatModuleService implements IModuleService { @Override public String getModuleName() { return "chatModule"; } @Override public void init(Context context) { } }
在ModuleA中呼叫:
//1、通過類名呼叫服務 IModuleService service = ARouter.getInstance().navigation(IModuleService.class); String getName = service.getModuleName(); Log.e("TTT", "getName is " + getName); //2、通過路徑名稱呼叫服務 IModuleService service1 = (IModuleService) ARouter.getInstance().build(MConstant.MODULE_SERVICE).navigation(); String getName1 = service1.getModuleName(); Log.e("TTT", "getName1 is " + getName1);
上面兩種方式都可以最終得到ModuleB中的資料。
2.6、降級方案
ARouter.getInstance().build("/xxx/xxx").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", "被攔截了"); } });
當跳轉失敗時,可以通過回撥得到結果並做相應處理。
三、引用
【1】ARouter:https://github.com/alibaba/ARouter
【2】APT、annotationProcessor、android-apt、Provided、自定義註解:
https://blog.csdn.net/xx326664162/article/details/68490059