这个寒假用空闲时间做了一个基于编译时注解的RxBus,目前还没有做工程化处理,但是基本的功能已经写好,欢迎大家star和fork
趁着寒假最后一天来写一下开发过程。
编译时注解总结
注解分为源码级注解、编译时注解与运行时注解,编译时注解和运行时注解时被经常用到的,但是运行时注解因为使用了反射机制,所以在性能上会有所降低,编译时注解就成了最受追捧的注解方式。
annotation
既然说是编译时注解,第一步当然是写注解的模块了,步骤如下:
- 新建java library(右键新建module)
- 编写注解,可以参考下面的
1 | @Target({ElementType.METHOD}) |
因为我们的注解是用在函数上的,所以Target就是ElementType.METHOD,还有下面几种值可以选择
根据需要注解的元素的类型来选择值。
注解处理器
准备
顾名思义,注解处理器就是用来处理注解的,而且是仅用来处理编译时注解的,要实现一个编译处理器,我们也要新建一个Java library来存放注解处理器,具体步骤如下:
- 新建Java library
- 在注解助力器的build.gradle中添加第一步所写的注解库,即
1 | compile project(':rxeventbusannotation') |
- 除了导入注解库外,我们还需要导入auto-service和javapoet这两个库,如下:
1 | implementation 'com.squareup:javapoet:1.10.0' |
编写注解处理器
在配置好依赖后,接下来就可以正式地来编写注解处理器了。
- 新建一个processor.java文件,继承AbstractProcessor,如下:
1 | public class RxEventBusProcessor extends AbstractProcessor{ |
- 添加注解,标志该注解处理器所处理的注解和版本
1 | @SupportedAnnotationTypes("site.gemus.rxeventbusannotation.Subscribe") |
- 还有注解auto-service为我们提供的服务,完成后如下:
1 | @AutoService(Processor.class) |
- 重写函数
我们一般只重写最主要的几个函数,如init和process,当然process是必须要重写的,而在init中我们可以获得必要的工具
像这样:
1 | private Messager mMessager; |
Messager可以帮助我们打印信息,因为在注解处理器库中,我们无法使用log来进行打印
可以这样使用:
1 | mMessager.printMessage(Diagnostic.Kind.WARNING, "Elements is empty!"); |
注:不要轻易使用ERROR,会导致编译错误
Element
Element可以用来获得我们所注解的元素的信息,可以这样获得相应注解所标注的元素的信息
1 | Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Subscribe.class); |
Element的子类有TypeElement、PackageElement和VariableElement等,我们在获取信息时可以将它转换成这些子类来获得更详细的信息,但是需要注意,并不是Element能转换到任意一个子类,譬如说我使用的注解是用来标记函数的,就能转换为ExecutableElement,而不能转换为TypeElement、PackageElement等。
Element的相关函数
- getEnclosingElement()
getEnclosingElement()这个函数的作用是获取上一个闭包元素,譬如说我的注解是在site.gemus.app.firstFragment这个类当中注解函数的,它的上一个闭包元素就是site.gemus.app.firstFragment,使用
1 | element.getEnclosingElement().toString(); |
获取到的就是site.gemus.app.firstFragment这串字符
- asType()
asType()函数的作用是获得元素的类型,而不是变量的名字
javapoet的使用
javapoet最终的作用是生成一个.java文件,我们需要先设想好生成后的代码,然后再进行使用,网上关于javapoet的资料有很多,就不一一介绍了,可以参考
特别要注意的是,我们使用javapoet导入包(import)的时候,javapoet只提供了静态导入,如果想正常导入的话,就要有意识地使用 $T 来导入包,下面就是后来改正的例子。
1 | ClassName eventMethodMessage = ClassName.get("site.gemus.rxeventbusannotation","EventMethodMessage"); |
这样javapoet才会正常地导入我们自己所写的类。