企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] > ARouter不仅实现了对基础组件的路由,而且其具有的Ioc功能也实现了对动作的路由,也就是跨模块API调用! > 可以理解为“通过URL找Class能实现的业务,ARouter都能实现”,这个概念要理解透彻! ## 使用 ### 添加注解 ~~~ // 在支持路由的页面上添加注解(必选) // 这里的路径需要注意的是至少需要有两级,/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(); ~~~ ## 源码解析 * arouter-annotation: ARouter路由框架所使用的全部注解,及其相关类 * arouter-compiler:注解编译处理器,引入“arouter-annotation”,在编译器把注解标注的相关目标类生成映射文件 * arouter-api:实现路由控制 总的来说,就是arouter-annotation实现了路由表结构的定义,arouter-compiler在编译期完成了 构造路由表逻辑的创建, arouter-api在运行期加载逻辑构建路由表,并实现路由控制 ## arouter-annotation ![](https://img.kancloud.cn/f8/01/f8014019a8ade822b90c2db67ce34da3_689x366.png) ### @Route @Route 是 ARouter 最重要的注解,也是路由最基本的节点,该注解主要用于描述路由中的路径URL信息,使用该注解标注的类将被自动添加至路由表中。 ~~~ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.CLASS) public @interface Route { //路径URL字符串 String path(); //组名,默认为一级路径名;一旦被设置,跳转时必须赋值 String group() default ""; //该路径的名称,用于产生JavaDoc String name() default "undefined"; //额外配置的开关信息;譬如某些页面是否需要网络校验、登录校验等 int extras() default Integer.MIN_VALUE; //该路径的优先级 int priority() default - ~~~ ### RouteMeta路由元信息 如果全部路由信息认为是一张表格,那么RouteMeta就是表格的一行,代表路由表的一条元信息。 ~~~ public class RouteMeta { private RouteType type; // 路由的类型: private Element rawType; // Raw type of route private Class<?> destination; // 目标Class private String path; // 路径URL private String group; // 分组 private int priority = -1; // 路由的优先级 private int extra; // 目标Class的额外配置开关信息;譬如某些页面是否需要网络校验、登录校验等 private Map<String, Integer> paramsType; // 目标Class的需要注入的参数 的参数名称:参数类型TypeKind } public enum RouteType {// 路由的类型 ACTIVITY(0, "android.app.Activity"), SERVICE(1, "android.app.Service"), PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"), CONTENT_PROVIDER(-1, "android.app.ContentProvider"), BOARDCAST(-1, ""), METHOD(-1, ""), FRAGMENT(-1, "android.app.Fragment"), UNKNOWN(-1, "Unknown route type"); int id; String className; } public enum TypeKind { //目标Class的需要注入的参数的参数类型 //基本类型 BOOLEAN, BYTE, SHORT, INT, LONG, CHAR, FLOAT, DOUBLE, //封装类型 STRING, PARCELABLE, OBJECT; //使用Json解 ~~~  ### @Interceptor拦截器注解 @Interceptor 是拦截器注解,拦截器是全应用全局的,不分module,只要集成进apk就起效 ~~~ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.CLASS) public @interface Interceptor { //该拦截器的优先级 int priority(); //该拦截器的名称,用于产生JavaDoc String name() default "Default"; } ~~~ ### @Autowired自动装载注解 @Autowired 是页面跳转时参数传递用的。目标Class中使用该注解标志的变量,会在页面被路由打开的时候,在调用Inject(“`)后自动赋予传递的参数值 ~~~ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.CLASS) public @interface Autowired { // Mark param's name or service name. String name() default ""; // If required, app will be crash when value is null. // Primitive type wont be check! boolean required() default false; // Description of the field String desc() default "No desc."; ~~~ ## arouter-compiler注解编译器 ![](https://img.kancloud.cn/54/7d/547d6147cf09266d12dec9324cda5b10_666x460.png) 实现了“自动注册映射关系”也就是在编译期间自动生成映射文件,所以该module其实就是实现了一些注解处理器,目标在于生成映射文件与辅助文件(构造路由表逻辑的创建) > 1\. 首先通过注解处理器扫出被标注的类文件;  > 2\. 然后按照不同种类的源文件进行分类,这是因为ARouter是一个框架,其能够提供的功能非常多,所以不仅仅提供了跳转功能,它也能够实现模块之间的解耦,除此之外ARouter还能够提供很多的功能,像刚才提到的拦截器可以实现自动注册,其实ARouter中的所有组件都是自动注册的  > 3\. 在按照不同种类的源文件进行分类完成之后,就能够按照固定的命名格式(工程名+$$+Group+$$+分组名)生成映射文件,这部分完成之后就意味着编译期的部分已经结束了 > 版权声明:本文为博主原创文章,转载请附上博文链接! 一般来说arouter-compiler所产生的class文件有以下几种: 1. 项目目录下的 XXX$$工程名$$Autowired. 为自动装载的辅助类,核心为inject函数,实现对目标对象的成员变量的赋值 2. routes目录下,分别是 **工程名$$Group$$分组名 【组内的路由清单列表】** (Map atlas  包含了对应分组下的,路由URL与目标对象Class的映射关系;  注意Router注解中无分组的话,默认以“/xx/xx”的第一个xx为分组名 **工程名$$Root$$$模块名 【组别的清单列表】** Map> routes  包含了组名与对应组内的路由清单列表Class的映射关系  是Arouter的“分组管理,按需加载”的实现。  ARouter在初始化的时候只会一次性地加载所有的root结点,而不会加载任何一个Group结点,这样就会极大地降低初始化时加载结点的数量  那么什么时候加载分组结点呢?其实就是当某一个分组下的某一个页面第一次被访问的时候,整个分组的全部页面都会被加载进去,这就是ARouter的按需加载 **工程名$$Providers$$模块名 【Ioc的动作路由清单列表】** Map providers  PROVIDER 类型的路由节点的清单列表  包含了使用依赖注入方式的某class(实现了IProvide接口的直接子类)的 路由URL 与class映射关系  目标Class都实现了IProvider接口,借此实现部分路由转到该清单中  需要注意的是:Ioc动作路由清单其实只是 Route注解的一种特殊用法,总的来说,还是一种URL与目标类的映射关系  其实想一下,依赖注入,无非也就是指定好目标接口的目标类,然而实例化后进行赋值。URL就是指定说明 **工程名$$Interceptors$$模块名 【模块内的拦截器清单列表】** Map> interceptors  包含了某个模块下的拦截器 与 优先级的映射关系  一个模块下的所有拦截器都在该类中包含,无分组特性,所以直接以模块名命名类文件 ### Route注解处理 **定义** ~~~ @Route(path = "/test/activity1") public class Test1Activity extends AppCompatActivity { //``` } ~~~ 那么官方处理器处理后生成的映射文件为 ![](https://uploader.shimo.im/f/6F16wozbrvMWJsoQ.png!thumbnail) 以工程名$$Group$$分组名 【组内的路由清单列表】 ~~~ public class ARouter\$\$Group\$\$test implements IRouteGroup { public ARouter\$\$Group\$\$test() { } public void loadInto(Map<String, RouteMeta> atlas) { atlas.put("/test/activity1", RouteMeta.build(RouteType.ACTIVITY, Test1Activity.class, "/test/activity4", "test", (Map)null, -1, -2147483648)); } } ~~~ ### Autowired注解处理 定义 ~~~ public class Test1Activity extends AppCompatActivity { @Autowired String name; @Autowired int age; @Autowired(name = "boy") boolean girl; @Autowired TestParcelable pac; @Autowired TestObj obj; private long hig ~~~ 生成 ~~~ public class Test1Activity\$\$ARouter\$\$Autowired implements ISyringe { private SerializationService serializationService; public Test1Activity\$\$ARouter\$\$Autowired() { } public void inject(Object target) { this.serializationService = (SerializationService)ARouter.getInstance().navigation(SerializationService.class); Test1Activity substitute = (Test1Activity)target; substitute.name = substitute.getIntent().getStringExtra("name"); substitute.age = substitute.getIntent().getIntExtra("age", 0); substitute.girl = substitute.getIntent().getBooleanExtra("boy", false); substitute.pac = (TestParcelable)substitute.getIntent().getParcelableExtra("pac"); if(null != this.serializationService) { substitute.obj = (TestObj)this.serializationService.json2Object(substitute.getIntent().getStringExtra("obj"), TestObj.class); } else { Log.e("ARouter::", "You want automatic inject the field \'obj\' in class \'Test1Activity\' , then you should implement \'SerializationService\' to support object auto inject!"); } substitute.url = substitute.getIntent().getStringExtra("url"); substitute.helloService = (HelloService)ARouter.getInstance().navigation(HelloService.class); ~~~ ### Interceptor注解处理 ~~~ @Interceptor(priority = 7) public class Test1Interceptor implements IInterceptor { //``` } public class ARouter\$\$Interceptors\$\$app implements IInterceptorGroup { public ARouter\$\$Interceptors\$\$app() { } public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) { interceptors.put(Integer.valueOf(7), Test1Interceptor.class); } ~~~ ## arouter-api路由控制 ARouter 的初始化过程最重要的一步一定是把前面编译产生的路由清单文件加载到内存,形成一个路由表,以供后面路由查找之用。 ## 参考资料 [阿里开源路由框架ARouter的源码分析](https://blog.csdn.net/fei20121106/article/details/73743235)