Android APT

Android APT

文章目录

APT annotation processing tool 注解处理工具

注解类型

  1. 注解语法

注解通过@interface关键字来定义

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface MyAnnotation {}

Java中总共有5中元注解:@Retention,@Documented,@Target,@Inherited,@Repeatable。下面分别介绍它们:

  1. @Retention
    用来说明注解的存活时间,有三种取值:

     RetentionPolicy.SOURCE:注解只在源码阶段保留,编译器开始编译时它将被丢弃忽视
     
     RetentionPolicy.CLASS:注解会保留到编译期,但运行时不会把它加载到JVM中
     
     RetentionPolicy.RUNTIME:注解可以保留到程序运行时,它会被加载到JVM中,所以程序运行过程中可以获取到它们
     例如我们常用的ButterKnife 使用的就是编译时期的注解,在编译时期通过javapoet生成对对应的代码
    
  2. @Target
    指定注解可作用的目标,取值如下:

ElementType.PACKAGE:可作用在包上
        
ElementType.TYPE:可作用在类、接口、枚举上
    
ElementType.ANNOTATION_TYPE:可以作用在注解上
    
ElementType.FIELD:可作用在属性上
    
ElementType.CONSTRUCTOR:可作用在构造方法上
    
ElementType.METHOD:可作用在方法上
    
ElementType.PARAMETER:可作用在方法参数上
    
ElementType.LOCAL_VARIABLE:可作用在局部变量上,例如方法中定义的变量
    
它接收一个数组作为参数,即可以指定多个作用对象,就像上面的Demo:
@Target({ElementType.FIELD, ElementType.TYPE})
  1. @Documented
    从名字可知,这个注解跟文档相关,它的作用是能够将注解中的元素包含到Javadoc中去。
  2. @Inherited
    Inherited是继承的意思,但并不是注解本身可被继承,而是指一个父类SuperClass被该类注解修饰,那么它的子类SubClass如果没有任何注解修饰,就会继承父类的这个注解。
    举个栗子:
@Inherited
@Target(ElementType.Type)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {}
    
@Test
public class A {}
    
public class B extens A {}
    
解释:注解Test被@Inherited修饰,A被Test修饰,B继承A(B上又无其他注解),那么B就会拥有Test这个注解。
  1. @Repeatable
    这个词是可重复的意思,它是java1.8引入的,算一个新特性。
    什么样的注解可以多次应用来呢,通常是注解可以取多个值,举个栗子:
    Person[] value();
}

@Repeatable(Persons.class)
public @Interface Person {
    String role() default ""
}

@Person("artist")
@Person("developer")
@Person("superman")
public class Me {}

解释:@Person被@Repeatable修饰,所以Person可以多次作用在同一个对象Me上,而Repeatable接收一个参数,这个参数是个容器注解,用来存放多个@Person。

注解的处理

运行时注解的处理

运行时的注解处理,一般是通过反射的方式获取到注解,然后进行自己想要的 处理,比如EventBus 的 线程处理的注解,在主线程或子线程,通过反射后在对应的线程里面进行处理!
例如

 /**
     * 解析注解InjectView
     *
     * @param activity 使用InjectView的目标对象
     */
    public static void inject(Activity activity) {
        Field[] fields = activity.getClass().getDeclaredFields();
        //通过该方法设置所有的字段都可访问,否则即使是反射,也不能访问private修饰的字段
        AccessibleObject.setAccessible(fields, true);
        for (Field field : fields) {
            boolean needInject = field.isAnnotationPresent(InjectView.class);
            if (needInject) {
                InjectView anno = field.getAnnotation(InjectView.class);
                int id = anno.id();
                if (id == -1) continue;
                View view = activity.findViewById(id);
                Class fieldType = field.getType();
                try {
                    //把View转换成field声明的类型
                    field.set(activity, fieldType.cast(view));
                } catch (Exception e) {
                    Log.e(InjectView.class.getSimpleName(), e.getMessage());
                }
            }
        }
    }

编译时注解的处理

编译时注解 需要注解处理器来协助处理对应的注解,一般情况下我们通过处理器获取注解之后通过javapoet来生成我们想要的文件,例如ButterKnife在编译时期就生成了findviewbyid的文件.

  • 处理步骤如下:
  1. annotation 和 AbstractProcessor需要建在两个不同的moudle中
  2. 继承 AbstractProcessor
@AutoService(Processor.class) //自动为我们注册annotation否则需要手动在META_INF下面手动注册
public class MyProcessor extends AbstractProcessor
{
    private Types    mTypeUtils;
    private Elements mElementUtils;
    private Filer    mFiler;
    private Messager mMessager;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment)
    {
        super.init(processingEnvironment);

        //初始化我们需要的基础工具
        mTypeUtils = processingEnv.getTypeUtils();
        mElementUtils = processingEnv.getElementUtils();
        mFiler = processingEnv.getFiler();
        mMessager = processingEnv.getMessager();
    }

    @Override
    public SourceVersion getSupportedSourceVersion()
    {
        //支持的java版本
        return SourceVersion.latestSupported();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes()
    {
        //支持的注解
        Set<String> annotations = new LinkedHashSet<>();
        annotations.add(ZyaoAnnotation.class.getCanonicalName());
        return annotations;
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment)
    {
        //这里开始处理我们的注解解析了,以及生成Java文件
        return false;
    }
}

javapoet

  • 例如我们想构建一个Activity
 public static void main(String[] args){
        //构建类
        TypeSpec.Builder classBuild=TypeSpec.classBuilder("HomeActivity")
                .addModifiers(Modifier.PUBLIC)
                .superclass(ClassName.get("android.app","Activity"));
        //构建方法
        MethodSpec onCreate= MethodSpec.methodBuilder("onCreate")
                .addAnnotation(ClassName.get("java.lang","Override"))
                .addModifiers(Modifier.PROTECTED)
                .addParameter(ClassName.get("android.os","Bundle"),"savedInstanceState")
                .addStatement("super.onCreate(savedInstanceState)")
                .addStatement("setContentView(R.layout.activity_main)")
                .build();
        //构建 文件
        JavaFile javaFile= JavaFile.builder("com.comers.processor",classBuild.addMethod(onCreate).build()).build();
        //写文件
        try {
            javaFile.writeTo(new File("/Volumes/world/works/NewFrame/app/src/main/java/com/comers/shenwu/kotlin"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

参考 https://www.jianshu.com/p/7454a933dcaf
https://blog.csdn.net/wsw_123/article/details/81018161
https://blog.csdn.net/weixin_34007020/article/details/87137483 //abstractProcessor 方法的详解
https://blog.csdn.net/wenyingzhi/article/details/80415014 //javaopet详解
https://blog.csdn.net/l540675759/article/details/82931785 //javapoet 详解
https://juejin.im/post/584d4b5b0ce463005c5dc444

上一篇:Javase——注解


下一篇:Spring中@Autowired、@Resource和@Inject注解的使用和区别