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项目)

更多相关文章

  1. Android(安卓)Studio NDK开发案例二 JNI包含多个cpp文件
  2. Android(安卓)vs. Moblin决战移动终端市场
  3. 我的 android studio ndk 开发笔记(1)
  4. OPhone/Android的学习(2)—从分析Eclipse自动生成的代码到以XML
  5. Android(安卓)Camera生成bmp格式的图片
  6. Android(安卓)Paging分页库的学习(二)—— 结合Room数据库进行分页
  7. Android(安卓)GreenDao使用总结(包括模型生成、增删改查、修改存
  8. 使用 buck 打包 Android( 使用OkBuck给Android(安卓)Studio+gradl
  9. Android(安卓)Odex

随机推荐

  1. android 实现由下至上弹出并位于屏幕底部
  2. Android(安卓)GPS状态改变与监听
  3. android 设置静态wifi地址
  4. Android(安卓)软键盘小知识点
  5. android短信发送器源代码
  6. android 客户端 smtp 协议发送数据
  7. Working with Images in Google's Androi
  8. android FlexboxLayout可伸缩布局
  9. Android(安卓)studio实现按钮的点击事件
  10. 『ANDROID』Android中的onWindowFocusCha