APT

作者: radish520like | 来源:发表于2018-05-22 17:38 被阅读0次

APT 简介

  APT 就是注解处理器,他是 javac 的一个工具,用来在编译时扫描和处理注解。一个注解处理器它以 Java 代码作为输入,生成文件(通常是 java 文件),这些生成的 java 文件不能修改,并且会和我们手动编写的 java 文件一样会被 javac 进行编译。
  这里我们简单模拟一下 ButterKnife 的原理,来讲解 APT.

简单使用

  首先我们新建一个项目,在项目中新建一个 Java Module,命名为 annotation,用于声明注解,然后在 annotation Module 中新建一个元注解类命名为 BindView

package com.radish.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//作用在属性上
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public @interface BindView {

    int value();
}

  然后我们再新建一个 Java Module 命名为 compiler(注意不是 Android Librarry,是 Java Library)

image.png
  然后在 compiler Moodule 中新建一个类,命名为 TestProcessor 并且 extends AbstractProcessor。
  首先,我们需要将我们自定义的注解处理器进行注册,在 build.gradle 中添加配置,然后修改代码
compile 'com.google.auto.service:auto-service:1.0-rc2'
package com.radish.compiler;

import com.google.auto.service.AutoService;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;


//自动注册
@AutoService(Processor.class)

public class TestProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false;
    }
}

  接下来,我们需要指定一些配置,比如说,该注解处理器可以处理什么样的注解,Java 版本是多少,初始化一些工具类等等。

package com.radish.compiler;

import com.google.auto.service.AutoService;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;


//自动注册
@AutoService(Processor.class)
//可以处理的注解,必须是全类名
@SupportedAnnotationTypes({"com.radish.annotation.BindView"})
//编译时候的 Java 版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class TestProcessor extends AbstractProcessor {

   /**
     * 日志工具
     */
    private Messager messager;
    /**
     * 文件工具
     */
    private Filer filer;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
        filer = processingEnv.getFiler();
    }

    /**
     *
     * @param annotations   使用了当前注解处理器允许处理的注解的节点集合
     *                      那些地方使用了我们可以处理的注解,被注解的节点就会放到 Set 集合中
     * @param roundEnv      环境
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

        return false;
    }
}

  接下来我们就需要了解最主要的一个方法 process,该法方法是一定会被调用的方法,就类似于 Java 中的 main 方法

    /**
     *
     * @param annotations   使用了当前注解处理器允许处理的注解的节点集合
     *                      那些地方使用了我们可以处理的注解,被注解的节点就会放到 Set 集合中
     * @param roundEnv      环境
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for(TypeElement typeElement : annotations){
            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(typeElement);
            for(Element element : elements){
                messager.printMessage(Diagnostic.Kind.NOTE,element.getSimpleName());
            }
        }
        return false;
    }

  然后,我们在 app Module 中引入 annotation Module:

//是 apt 中的一种工具,是 google 开发的内置框架,不需要引入,直接在 build.gralde 文件中引入
annotationProcessor project(':compiler')
compile project(':annotation')

这样就可以开始使用注解了

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.tv)
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

  然后我们 make 一下 app


image.png

  目前我们 process 中拿到的被注解的节点是 tv

    /**
     *
     * @param annotations   使用了当前注解处理器允许处理的注解的节点集合
     *                      那些地方使用了我们可以处理的注解,被注解的节点就会放到 Set 集合中
     * @param roundEnv      环境
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for(TypeElement typeElement : annotations){
            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(typeElement);
            for(Element element : elements){
//                messager.printMessage(Diagnostic.Kind.NOTE,element.getSimpleName());
                //获取其父节点(tv 的父节点:MainActivity)
                Element enclosingElement = element.getEnclosingElement();
                /*
                    假如我们需要创建一个类,假如叫 MainActivity_Binding
                    enclosingElement.getSimpleName().toString() + "_Binding";
                    但是类里面的代码,都需要字符串的拼接,比较繁琐而且容易出错,
                    那么我们就可以借助 javapoet 来进行 java 文件的创建
                 */
            }
        }
        return false;
    }

JavaPoet

  在 build.gradle 添加一行配置compile 'com.squareup:javapoet:1.7.0',其github 的网址是:

https://github.com/square/javapoet

    /**
     *
     * @param annotations   使用了当前注解处理器允许处理的注解的节点集合
     *                      那些地方使用了我们可以处理的注解,被注解的节点就会放到 Set 集合中
     * @param roundEnv      环境
     * @return
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for(TypeElement typeElement : annotations){
            Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(typeElement);
            for(Element element : elements){
                //获取其父节点(tv 的父节点:MainActivity)
                Element enclosingElement = element.getEnclosingElement();
                String className = enclosingElement.getSimpleName() + "_Binding";
                MethodSpec main = MethodSpec.methodBuilder("main")
                        .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                        .returns(void.class)
                        .addParameter(String[].class, "args")
                        .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
                        .build();

                TypeSpec helloWorld = TypeSpec.classBuilder(className)
                        .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                        .addMethod(main)
                        .build();

                JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
                        .build();

                try {
                    javaFile.writeTo(filer);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

  然后我们 make app,java 文件就生成了。


image.png
package com.example.helloworld;

import java.lang.String;
import java.lang.System;

public final class MainActivity_Binding {
  public static void main(String[] args) {
    System.out.println("Hello, JavaPoet!");
  }
}

  然后我们就可以在我们的类中去使用这个生成的 java 类了。


image.png

如何调试注解处理器

image.png
image.png
image.png
image.png
image.png
image.png
image.png

  然后就可以开始 debug 调试模式了

相关文章

  • apt与apt-get

    Linux中apt与apt-get命令的区别与解释 apt与apt-get 在开始对比 apt 与 apt-get...

  • Linux环境下安装Mysql数据库并通过远程连接

    安装 apt yum install apt 更新 apt sudo apt-get update 安装mysql...

  • Ubuntu 下载Docker 详细教程

    更新apt源 sudo apt-get update sudo apt-get install apt-trans...

  • dpkg软件包管理

    apt-get apt-get [选项] action <参数> apt-cache apt-file dpkg ...

  • Ubuntu一些问题

    1. apt-get 提示找不到apt,请执行apt-get install apt apt都被整没了??发现敲n...

  • 基于APT的android路由框架(二)--APT技术

    Android 中的APT 基于APT的android路由框架(一) 一、什么是APT APT(Annotatio...

  • APT

    APT 简介   APT 就是注解处理器,他是 javac 的一个工具,用来在编译时扫描和处理注解。一个注解处理器...

  • apt

    AutoService会自动在META-INF文件夹下生成Processor配置信息文件,该文件里就是实现该服务接...

  • APT

    APT-概念了解 友情链接: https://lizhaoxuan.github.io/2016/07/17/ap...

  • apt

    翻译:选择送花很少出错。 An apt choose of sending flower has rarely w...

网友评论

      本文标题:APT

      本文链接:https://www.haomeiwen.com/subject/yzfkjftx.html