android进阶---【注解(二)之自定义编译期注解】


之前在 android进阶—【注解(一)】中简单介绍了注解的使用和自定义运行时注解。
那么更劲爆、更有料的 自定义编译期注解来了!

在 JDK 1.5 之后,Java 语言提供了对注解(Annotation)的支持,这些注解和普通的 Java 代码一样,是在运行期间发挥作用的。在JDK 1.6 中实现了JSR-269 规范。提供了一组插入式注解处理器的标准 API 在编译期间对注解进行处理,我们可以把它看做是一组编译器的插件,在这些插件里面,可以读取,修改,添加抽象语法书中的任意元素。

自定义编译期注解

编译注解主要是在编译过程中,生成必要的文件,这样在运行时调用,就不需要再通过大量的反射(低效)来进行操作。

这种形式大大提高了注解在运行时的效率,但同时也增加了编译的时间。当然,编译时间的长短我们无所谓啦。

1.基本知识了解

1.1APT

APT(Annotation Processing Tool)是javac内置的工具,用于在编译时期扫描和处理注解信息。它对源代码文件进行检测找出其中的Annotation,根据注解自动生成代码(调用注解处理器的Process方法生成源文件)。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。

1.2AbstractProcessor

AbstractProcessor是javax.annotation.processing包下的一个抽象类。但是,Android平台是基于OpenJDK的,而OpenJDK中不包含Annotation Processor的相关代码。

因此,在使用Annotation Processor时,必须在新建Module时选择Java Library
在这里插入图片描述
在这里插入图片描述

2.AbstractProcessor的API介绍

常用方法名作用
init(…)初始化工作
getSupportedSourceVersion()指定当前注解器使用的Jdk版本
getSupportedAnnotationTypes()指出注解处理器 支持处理哪种注解
process(…)APT扫描到注解后调用方法
2.1.void init(ProcessingEnvironmentprocessingEnv)方法:

做一些初始化工作,注释处理工具会调用此方法,并传过来processingEnv参数。
通过ProcessingEnvironment 可以获取到很多可操作类,如:

操作类
Elements es = processingEnvironment.getElementUtils();
Filer filer = processingEnvironment.getFiler();
Types types = processingEnvironment.getTypeUtils();
Messager messager = processingEnvironment.getMessager();
SourceVersion version = processingEnvironment.getSourceVersion();
  • Elements
    用来对程序元素进行操作的实用工具方法。
  • Filer
    在生成java文件时候使用。javapoet配合使用
  • Types
    用来对类型进行操作的实用工具方法。
  • Messager
    提供注释处理器用来报告错误消息、警告和其他通知的方式。可以传递元素、注释和注释值,以提供消息的位置提示。
    例如:
messager.printMessage(Diagnostic.Kind.ERROR,"类出现错误",typeElement);
  • SourceVersion
    对应getSupportedSourceVerrsion()
2.2SourceVersion getSupportedSourceVersion()

指定当前注解器使用的Jdk版本
在 jdk1.7 中,我们可以使用注解 @SupportedSourceVersion()代替

2.3.Set getSupportedAnnotationTypes()

指出注解处理器 处理哪种注解
在 jdk1.7 中,我们可以使用注解 @SupportedAnnotationTypes()代替

2.4.boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
  • RoundEnvironment
常用方法名含义
errorRaised()如果在以前的处理 round 中发生错误,则返回 true;否则返回 false。
getElementsAnnotatedWith(…)返回使用给定注释类型注释的元素。
  • Element
子类说明
ExecutableElement表示某个类或接口的方法、构造方法或初始化程序(静态或实例),包括注释类型元素。对应@Target(ElementType.METHOD) @Target(ElementType.CONSTRUCTOR)
TypeElement表示一个类或接口程序元素。提供对有关类型及其成员的信息的访问。注意,枚举类型是一种类,而注释类型是一种接口。对应@Target(ElementType.TYPE)
VariableElement表示一个字段、enum 常量、方法或构造方法参数、局部变量或异常参数。对应 @Target(ElementType.LOCAL_VARIABLE)
PackageElement表示一个包程序元素。提供对有关包及其成员的信息的访问。对应@Target(ElementType.PACKAGE)
TypeParameterElement表示一般类、接口、方法或构造方法元素的形式类型参数。对应@Target(ElementType.PARAMETER)
  • asType()
    返回此元素定义的类型 TypeMirror。

  • getEnclosingElement()
    返回封装此元素(非严格意义上)的最里层元素。

  • getKind()
    返回此元素的类型。

  • getModifiers()
    返回此元素的修饰符,不包括注释。

  • getSimpleName()
    返回此元素的简单(未限定)名称。

3.注册注解处理器

两种方法:
1.使用apt。
一个个人写的第三方jar,在谷歌出了annotationProcessor之后,停止了更新,并建议大家使用官方出品。所以这里咱们不再了解了。
2.官方出品,使用简单方便。
只需导入'com.google.auto.service:auto-service:1.0-rc3'jar包即可
在自定义的AbstractProcessor上使用 @AutoService(Processor.class)(com.google.auto相关包)注解,便可自动为 JAVA Processor 生成 META-INF 信息。
然后,在调用时,使用annotationProcessor 引用即可
例如:

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    
    annotationProcessor project(':processer')
    implementation project(':anna')
//    implementation project(':processer') //不行
}

4.处理注解逻辑,生成java文件

在onprocess方法中执行

一般处理器处理逻辑:

  • 遍历得到源码中,需要解析的元素列表。
  • 判断元素是否可见和符合要求。
  • 组织数据结构得到输出类参数。
  • 输入生成java文件。
  • 错误处理。

有多种方法可以实现生成java文件:
1.直接使用字符串拼接:

	/**
 * 字符串拼接形式  生成文件
 * @param className 类名
 * @param output  注解名
 */

private void createFile(String className, String output) {
    StringBuilder cls = new StringBuilder();
    cls.append("package apt;\n\npublic class ")
            .append(className)
            .append(" {\n  public static void main(String[] args) {\n")
            .append("    System.out.println(\"")
            .append(output)
            .append("\");\n  }\n}");
    try {
        JavaFileObject sourceFile = filer.createSourceFile("apt." + className);
        Writer writer = sourceFile.openWriter();
        writer.write(cls.toString());
        writer.flush();
        writer.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2.使用javapoet框架,更简单。
javapoet的使用,请看下一篇文章。

5.如何进行debug?

5.1.配置端口和jvm参数

找到项目目录下的gradle.properties 文件,打开:
在这里插入图片描述
将原先的 org.gradle.jvmargs=-Xmx1536m注掉。
改为

org.gradle.daemon=true
org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

当然,最后的5005端口是可以修改的

5.2.Android studio 的debug配置

在这里插入图片描述

5.3.在Terminal控制台输入gradlew --daemon开启守护线程(我好像没有做这一步,也可以)

在这里插入图片描述

5.4.开启debug模式

在这里插入图片描述
成功后会在Debug界面出现如下:
在这里插入图片描述

有时候会出现:
Error running “AnnotationProcessor” 
Unable to open debugger port{localhost:5005}:java.net.ConnectException”Connection refused:connect”的错误,这个时候把端口号换下改成其他的试试(有可能是占用了)。

在这里插入图片描述

5.5最后一步

在Terminal控制台中输入gradlew clean assembleDebug即可

然后,每次需要调试注解处理器时候,只需要选中之前配置的在这里插入图片描述,点击在这里插入图片描述,然后,再在Terminal控制台中输入gradlew clean assembleDebug即可(或者点击rebuild


再次感谢以下朋友的分享文章:
比较全面的介绍编译时注解的使用, 自定义运行时注解、编译时注解[ButterKnife原理探析]

Java编译时注解处理器(Annotation Processor)详解

Android 自定义注解详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安静的码字猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值