本系列文章主要分析 ARouter 框架的原理。
这篇文章 里面的一些内容来自:
https://github.com/alibaba/ARouter/blob/master/README_CN.md
官网对其使用已经总结的很好了,本篇博文在其基础上整理了下~~
1 简单介绍
对于 ARouter 大家只要做过模块化开发,那么就一定有所了解,ARouter 是阿里巴巴开源的一款路由框架,用于解决模块化开发中的模块依赖。
2.1 主要模块
官方提供了下面的四个插件模块:
- arouter-api:对外提供功能相关的 Api;
- arouter-compiler:用于解析注解,生成代码;
- arouter-register:用于 App 加固时的自动注册;
- arouter-idea-plugin:Idea 插件,用于关联路径和目标类;
2.2 功能介绍
官方文档中讲到 ARouter 支持如下的功能:
- 支持直接解析标准 URL 进行跳转,并自动注入参数到目标页面中;
- 支持多模块工程使用;
- 支持添加多个拦截器,自定义拦截顺序;
- 支持依赖注入,可单独作为依赖注入框架使用;
- 支持 InstantRun;
- 支持 MultiDex; (Google 方案)
- 映射关系按组分类、多级管理,按需初始化;
- 支持用户指定全局降级与局部降级策略;
- 页面、拦截器、服务等组件均自动注册到框架;
- 支持多种方式配置转场动画;
- 支持获取 Fragment;
- 完全支持 Kotlin 以及混编;
- 支持第三方 App 加固;(使用 arouter-register 实现自动注册)
- 支持生成路由文档;
- 提供 IDE 插件便捷的关联路径和目标类;
2 ARouter 使用(官网整理)
以下内容来自对 https://github.com/alibaba/ARouter/edit/master/README_CN.md 的整理:
2.1 Gradle 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| android { defaultConfig { ... javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } } }
dependencies { compile 'com.alibaba:arouter-api:x.x.x' annotationProcessor 'com.alibaba:arouter-compiler:x.x.x' ... }
|
这里两个库均要使用最新版本,防止兼容问题发生;
2.2 基本使用
2.2.1 添加注解
1 2 3 4
| @Route(path = "/test/activity") public class YourActivity extend Activity { ... }
|
2.2.2 初始化操作
1 2 3 4 5 6 7 8 9
| if (isDebug()) { ARouter.openLog(); ARouter.openDebug(); } ARouter.init(mApplication);
|
2.2.3 路由跳转
1 2 3 4 5 6 7 8 9
| ARouter.getInstance().build("/test/activity").navigation();
ARouter.getInstance().build("/test/1") .withLong("key1", 666L) .withString("key3", "888") .withObject("key4", new Test("Jack", "Rose")) .navigation();
|
2.3 进阶使用
2.3.1 通过 URL 跳转
我们除了可以使用 @Route 方式指定 path 来跳转,我们还可以通过 url 跳转:
当通过 URL 跳转时,URL 中不能传递 Parcelable 类型数据,通过 ARouter api 才能传递 Parcelable 对象;
1 2 3 4 5 6 7 8 9 10 11 12
|
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 中的配置:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <activity android:name=".activity.SchameFilterActivity"> <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>
|
2.3.2 自动解析参数
自动解析参数。
为每一个参数声明一个字段,并使用 @Autowired 标注,我们传递的值将会自动赋值给所属变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Route(path = "/test/activity") public class Test1Activity extends Activity { @Autowired public String name; @Autowired int age; @Autowired(name = "girl") boolean boy; @Autowired TestObj obj; @Autowired List<TestObj> list; @Autowired Map<String, List<TestObj>> map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ARouter.getInstance().inject(this); } }
|
如果需要传递自定义对象(比如上面的 TestObj),新建一个类,实现 SerializationService, 并使用 @Route 注解标注!
这个类的作用是自定义对象的序列化方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @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); }
@Override public String object2Json(Object instance) { return JSON.toJSONString(instance); } }
|
这里使用的是 JSON 序列化。
2.3.3 跳转拦截器
拦截器用于拦截跳转过程,面向切面编程,比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查!
拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Interceptor(priority = 8, name = "测试用拦截器") public class TestInterceptor implements IInterceptor { @Override public void process(Postcard postcard, InterceptorCallback callback) { ... callback.onContinue(postcard); }
@Override public void init(Context context) { } }
|
上面说的初始化,就是 ARouter.init 方法;
2.3.4 处理跳转结果
navigation 方法支持传入一个 NavigationCallback 回调,处理跳转结果:
1 2 3 4 5 6 7 8 9 10 11
| ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() { @Override public void onFound(Postcard postcard) { ... }
@Override public void onLost(Postcard postcard) { ... } });
|
2.3.5 自定义全局降级策略
自定义类,实现 DegradeService 接口,并加上一个 Path 内容任意的注解:
1 2 3 4 5 6 7 8 9 10 11
| @Route(path = "/xxx/xxx") public class DegradeServiceImpl implements DegradeService { @Override public void onLost(Context context, Postcard postcard) { } @Override public void init(Context context) { } }
|
2.3.6 为目标页面声明更多信息
@Route 还有一个 extras 属性,用于设置一些额外的属性,他是一个 int 值,有 32 位,可以配置 32 个开关;
我们可以通过设置指定的开关位,然后在拦截器中可以拿到这个标记进行业务逻辑判断!
1 2 3 4
| @Route(path = "/test/activity", extras = Consts.XXXX) public class Test1Activity extends Activity { ... ... ... }
|
2.3.7 依赖注入解耦
ARouter 通过定义统一的访问接口来实现解耦 module 依赖;
核心接口:IProvider!
2.3.7.1 暴露服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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) {
} }
|
暴漏的服务,需要通过 @Route 注解去修饰!
2.3.7.2 访问服务
当我们暴漏了服务后,需要
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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 的方式发现服务)
1 2
| helloService.sayHello("Vergil"); helloService2.sayHello("Vergil");
|
使用依赖查找的方式发现服务,主动去发现服务并使用,也有 byName 和 byType 两种方式:
1 2 3 4
| helloService3 = ARouter.getInstance().navigation(HelloService.class); helloService4 = (HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation(); helloService3.sayHello("Vergil"); helloService4.sayHello("Vergil");
|
2.3.8 预处理服务
预处理服务和拦截器的概念很类似:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Route(path = "/xxx/xxx") public class PretreatmentServiceImpl implements PretreatmentService { @Override public boolean onPretreatment(Context context, Postcard postcard) { }
@Override public void init(Context context) {
} }
|
3 源码结构
我们来看下 ARouter 的源码结构,下面列出关键的目录:
1 2 3 4 5 6 7 8
| |-ARouter-master.iml |-README_CN.md |-arouter-api |-arouter-idea-plugin |-arouter-compiler |-arouter-annotation |-arouter-gradle-plugin |- ... ... ...
|
这里分别解释下每个 module 的作用:
- arouter-annotation:
- arouter-api:
- 对应 “arouter-api” 插件,对外提供功能相关的 Api;
- arouter-compiler:
- 对应 “arouter-compiler” 插件,用于解析注解,生成代码;
- arouter-gradle-plugin:
- 对应 “arouter-register” 插件,用于 App 加固时的自动注册;
- arouter-idea-plugin:
- 对应 “arouter-idea-plugin” 插件,用于关联路径和目标类;
3.1 Module 依赖关系
下图我们来看看这几个 module 的依赖关系:
依赖关系还是很简单的,毕竟只有几个 module。
4 总结
本篇博文整理了下 ARouter 官网的一些内容,总结了 ARouter 的基本使用和进阶使用,接下来,会通过分析每个 module 的源码,来进一步分析 ARouter 的原理!