美文网首页app应用开发框架
来说说 ARouter 是如何使用注解的

来说说 ARouter 是如何使用注解的

作者: jkwen | 来源:发表于2021-06-07 23:26 被阅读0次

    我们都知道 ARouter 实现页面跳转很简单,在 Activity 上加上 @Router 注解,就能通过这个路径完成跳转。可如果去看调用方法的实现,并不能一眼看出实现原理。所以就有了这篇文章,要想了解整个实现环节,还得从注解角度去分析。

    内容主要分为两部分,一部分是 Java 注解,借此机会大致了解些,但不会都介绍;另一部分是 APT 机制,这个是我新了解的,了解了这个,再去看很多第三方框架,你会发现透彻很多。

    ARouter 里用到的 Java 注解

    就以 Route 为例展开分析,

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.CLASS)
    public @interface Route {
        String path();
        String group() default "";
        String name() default "";
        //省略
    }
    

    第一行的 @Target 表示 Route 注解是哪种 Java 成员。@Target 也是一个注解,以它为例,再展开看看,

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        ElementType[] value();
    }
    

    从 Target 的方法 value() 来看可以指定多种类型,不过 Route 只赋值了一种,即 ElementType.TYPE,表示 类,接口或者枚举,这里先简单理解为类。ElementType 是个枚举类,里面还有其他值,例如 FIELD, METHOD 等等。

    再说 Target 注解,@Decumented 表示 Target 包含在用户文档中,了解即可。@Retention 表示 Target 是怎么保存的,例如只在代码中不被编译器识别,还是仅编入 class 文件,或者运行时通过反射访问。这里值是 RetentionPolicy.RUNTIME 表示保存在会被编入 class 文件,并可以通过运行时反射访问,RetentionPolicy 也是一个枚举类。

    最后 Target 注解也有一个 @Target,其值表示它的类型是注解声明。

    回看 Route 注解,这里我们就知道了它的类型是 Java 类,并且仅编入 class 文件保存。(这里可以先记住,后面可以自己留意下为什么这么做)

    关于 Java 注解可以看下这个更详细的介绍。Java 注解

    ARouter 如何使用 APT

    APT(注解处理器),可以将运行时用反射处理注解的过程提前到编译时期,从而提高效率。它的作用是,项目编译时拿到相应的注解和被注解对象,从而依照需求自动生成一些代码。

    在项目引入 ARouter 框架时,需要像这样添加依赖,

    //以 kotlin 为例
    implementation 'com.alibaba:arouter-api:1.5.1'
    kapt 'com.alibaba:arouter-compiler:1.5.1'
    

    为什么别的依赖一行就够了,而 ARouter 需要两行,原因在于 ARouter 使用了 APT,一个 APT 项目要求,至少有两个 Java Library 模块。一个是 Annotation 模块用于存放自定义注解,一个 Compiler 模块,用于存放自定义注解处理器。

    对照着 ARouter 在 github 上的项目工程,可以找到 arouter-annotation 和 arouter-compiler 这两个 Module。

    想要实现对注解的处理,就要通过继承 Java 的 AbstractProcessor 抽象类来实现。前面为什么是 Java 库模块,因为 Android 库模块里没有 AbstractProcessor,这个类主要的方法有这么几个,

    //表示处理器支持的注解
    //也可以利用 @SupportedAnnotationTypes 以注解参数的形式添加
    public Set<String> getSupportedAnnotationTypes() 
    //表示处理器支持的最新版本,默认是 1.6 版本
    //也可以利用 @SupportedSourceVersion 以注解参数的形式指定
    public SourceVersion getSupportedSourceVersion()
    //初始化处理器,重点在于 ProcessingEnvironment 类型,这里面包含着很多信息
    public synchronized void init(ProcessingEnvironment processingEnv)
    //唯一一个抽象方法
    //自定义处理器的工作也在此方法里
    public abstract boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);
    

    参考 arouter-compiler Module 里的 processor 包,BaseProcessor 继承自 AbstractProcessor 应该是做一些公共操作,先不管,再看 RouteProcessor 继承自 BaseProcessor,这个应该就是用来做 Route 注解处理的处理器。

    @AutoService(Processor.class)
    @SupportedAnnotationTypes({ANNOTATION_TYPE_ROUTE, ANNOTATION_TYPE_AUTOWIRED})
    public class RouteProcessor extends BaseProcessor {
        @Override
        public synchronized void init(ProcessingEnvironment processingEnv){}
        
        public boolean process(Set<? extends TypeElement> annotations,RoundEnvironment roundEnv){}
    }
    

    从第一行开始看,@AutoService 注解帮助我们自动生成一个文件,可以理解为我们自定义注解处理器后需要做一步这样的配置,而 @AutoService 就能帮我们完成这步,省去了人工操作。注意需要添加相应的依赖才能使用,AutoService

    //arouter 源码里是这样引用的
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'
    compileOnly 'com.google.auto.service:auto-service-annotations:1.0-rc7'
    

    第二行就是前面说的处理器支持的类型,显然它支持 Route 和 AutoWired,但这两个常量的值其实是带上包名的路径,"com.alibaba.android.arouter.facade.annotation.Route" 和 "com.alibaba.android.arouter.facade.annotation.Autowired" 根据这个路径,其实指到的也就是 Route 和 Autowired 注解。

    再往下就是 RouteProcessor 的主要工作了,分两部分,一部分是初始化工作,一部分是 process 工作。最终的目标就是根据注解生成相应的类代码,但如果结构化编写很容易出错,鉴于面向对象的思想,可能会更好理解,所以就有了 JavaPoet 这个库,果然就是有需求就会有产出。

    //arouter 源码里是这样引用的
    implementation 'com.squareup:javapoet:1.8.0'
    

    所以综合来看,ARouter 采用了 APT 机制来帮助框架自动生成一些代码,并且将生成时机提前至编译器,这样一来,效率就提高了。

    参考内容

    编译时注解处理器(APT)详解

    相关文章

      网友评论

        本文标题:来说说 ARouter 是如何使用注解的

        本文链接:https://www.haomeiwen.com/subject/jgnreltx.html