Java中的APT注解
java中常用的一些框架都使用到了注解,比如EventBus、Dragger2、Butterknife等,从这些流行框架可以看出,注解在Android中使用还是很广泛的,常见的注解有运行时注解和编译期注解,运行时注解是通过反射在运行时拿到注解信息进行处理,编译期注解是在编译阶段根据注解生成相应的中间类来处理注解,因为运行时注解需要在运行时执行反射代码和注解处理逻辑,所以它的运行时性能没有编译期注解高,本文学习的注解方式就是APT编译时注解。
1、创建一个名称为annotation的module用来单独存放自定义的注解类,然后在该模块下可以新建一个自定义的注解类(这里以HuiAnnotation为例)
/** * Created by znh on 2020/7/29 * * 自定义注解 */
@Target(ElementType.TYPE)//作用在类上@Retention(RetentionPolicy.CLASS)//编译期注解public @interface HuiAnnotation { }
2、创建一个名称为processor的module用来存放注解处理器,这个模块中需要处理上一步中自定义的注解,所以需要将annotation模块引入进来,自定义的注解处理器需要继承至谷歌注解处理器框架中的AbstractProcessor类,所以需要引入注解处理器框架,为了更好的生成java模板代码,还可以引入javapoet代码模板生成框架(这个不是必须的,使用它可以更方便的生成java代码),以上3个依赖包在gradle中的依赖配置如下:
//添加注解处理器依赖implementation 'com.google.auto.service:auto-service:1.0-rc6'//gradle5.0及以上需要annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'//添加自定义的注解类依赖implementation project(':annotation')//用来生成java模板代码的框架implementation 'com.squareup:javapoet:1.11.1'
然后在该模块下新建一个注解处理器类(这里以HuiProcessor为例),这个自定义的注解处理器类中有几个比较重要的方法需要重写:
- @AutoService(Processor.class):要为注解处理器添加上这个注解才可以生效
- init(ProcessingEnvironment processingEnvironment):做一些初始化的操作
- getSupportedAnnotationTypes():支持的注解有哪些,将自己定义的注解添加进去
- getSupportedSourceVersion() :支持的jdk版本号
- process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment):注解处理的核心方法,注解处理逻辑就是在这个方法中写的
注解处理器HuiProcessor的代码如下:
/** * Created by znh on 2020/7/29 * * 自定义注解处理器 */
@AutoService(Processor.class)public class HuiProcessor extends AbstractProcessor { private Elements mElementUtils; private Messager mMessager; /** * 做一些初始化操作 * * @param processingEnvironment */ @Override public synchronized void init(ProcessingEnvironment processingEnvironment) { super.init(processingEnvironment); mElementUtils = processingEnvironment.getElementUtils(); mMessager = processingEnvironment.getMessager(); } /** * 支持的注解有哪些 * * @return */ @Override public Set<String> getSupportedAnnotationTypes() { Set<String> annotationTypes = new LinkedHashSet<>(); annotationTypes.add(HuiAnnotation.class.getCanonicalName()); return annotationTypes; } /** * 支持的jdk版本 * * @return */ @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } /** * 注解核心处理方法 * * @param set * @param roundEnvironment * @return */ @Override public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) { //没有需要处理的注解 if (set.isEmpty()) return false; //获取项目中使用了HuiAnnotation注解的元素集合 Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(HuiAnnotation.class); //遍历elements for (Element element : elements) { //获取元素的包名 String packageName = mElementUtils.getPackageOf(element).getQualifiedName().toString(); //获取元素的类名 String className = element.getSimpleName().toString(); //自定义需要生成的类文件名称 String customClassName = className + "Helper"; //打印日志 mMessager.printMessage(Diagnostic.Kind.NOTE, "packageName:" + packageName); mMessager.printMessage(Diagnostic.Kind.NOTE, "className:" + className); mMessager.printMessage(Diagnostic.Kind.NOTE, "customClassName:" + customClassName); //创建一个方法参数 ParameterSpec msgParam = ParameterSpec .builder(String.class, "msg") //定义参数类型和参数名称 .build(); //生成方法 MethodSpec print = MethodSpec.methodBuilder("print") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .returns(String.class) .addStatement("$T.out.println($S)", System.class, "Hello," + customClassName)//定义打印语句 .addParameter(msgParam) .addStatement("return $N", msgParam) .build(); //生成类 TypeSpec customClassType = TypeSpec.classBuilder(customClassName) .addModifiers(Modifier.PUBLIC) .addMethod(print) .build(); //生成java文件 JavaFile javaFile = JavaFile.builder(packageName, customClassType).build(); try { javaFile.writeTo(processingEnv.getFiler()); } catch (IOException e) { e.printStackTrace(); } } return true; }}
3、这个注解处理器的作用是生成一个类名为自定义的customClassName中间辅助类,在这个类中生成一个能打印信息的方法。注解和注解处理器定义完成之后就可以在项目中使用了,在app的module中使用时需要将注解和注解处理器依赖进去,gradle配置如下:
implementation project(':annotation')annotationProcessor project(':processor')
然后在需要的类上添加注解并编译项目,会生成一个中间辅助类:
然后可以调用生成的中间辅助类的方法去完成自己的业务逻辑了,使用代码如下:
package com.znh.aptdemo;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import com.znh.annotation.HuiAnnotation;@HuiAnnotation //为MainActivity添加注解public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); test(); } public void test() { //调用中间类的方法进行测试 String msg = MainActivityHelper.print("测试一下..."); System.out.println(msg); }}打印结果如下:13077-13077/com.znh.aptdemo I/System.out: Hello,MainActivityHelper13077-13077/com.znh.aptdemo I/System.out: 测试一下...
Demo地址:https://github.com/huihuigithub/blog_demo_projects (java_apt_demo项目)
更多相关文章
- Android(安卓)Studio NDK开发案例二 JNI包含多个cpp文件
- Android(安卓)vs. Moblin决战移动终端市场
- 我的 android studio ndk 开发笔记(1)
- OPhone/Android的学习(2)—从分析Eclipse自动生成的代码到以XML
- Android(安卓)Camera生成bmp格式的图片
- Android(安卓)Paging分页库的学习(二)—— 结合Room数据库进行分页
- Android(安卓)GreenDao使用总结(包括模型生成、增删改查、修改存
- 使用 buck 打包 Android( 使用OkBuck给Android(安卓)Studio+gradl
- Android(安卓)Odex