Android APT

APT annotation processing tool 注解处理工具

注解类型

注解语法

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

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

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

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

RetentionPolicy.SOURCE:注解只在源码阶段保留,编译器开始编译时它将被丢弃忽视

RetentionPolicy.CLASS:注解会保留到编译期,但运行时不会把它加载到JVM中

RetentionPolicy.RUNTIME:注解可以保留到程序运行时,它会被加载到JVM中,所以程序运行过程中可以获取到它们
例如我们常用的ButterKnife 使用的就是编译时期的注解,在编译时期通过javapoet生成对对应的代码

@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})

@Documented
从名字可知,这个注解跟文档相关,它的作用是能够将注解中的元素包含到Javadoc中去。

@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这个注解。

@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的文件.

处理步骤如下:

  • annotation 和 AbstractProcessor需要建在两个不同的moudle中
  • 继承 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值