Android开发 APT技术

2021-06-09  本文已影响0人  雨来

APT

annotation process Tool 简称apt 也就是注解处理器的意思 像android中的三方库 最新版的eventBus Dagger2 等都是使用的这个技术 首先我们要 懂java中的注解的概念

什么是注解annotation

java中的注解 是描述java代码的元数据 它是不会影响java代码的运行的,但我们可以获取注解上的数值参于一定的计算和逻辑的

通过APT可以做什么

我们可以通过apt帮我们生成 按我们的规则制定的 java类文件

下面是例子可以直接运行(虽然没有什么意义但可以生成文件 逻辑逻辑大家可以按你们的业务来)

结构图:(3是依赖 1和2)

1和2都是java library


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

具体代码:

Annotation library

provider接口 这个接口没有什么用

public interface Provider {
}

RouteAnnotation 这个注解

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface RouteAnnotation {
    String name() default "MainActivity";
}
Annotation-complier 这个 library

注解处理器 AnnotationProcess 类

package com.www.annotation_complier;

/**
 * @author yulai
 * @time:
 */


import com.google.auto.service.AutoService;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import com.www.annotation.Provider;
import com.www.annotation.RouteAnnotation;

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;

//这个一定要写
@AutoService(Processor.class)
public class AnnotationProcess extends AbstractProcessor {

    private Filer mFiler; //这个filer类主要是为了生成java文件

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

    @Override
    public SourceVersion getSupportedSourceVersion() {
//        return super.getSupportedSourceVersion();
        return SourceVersion.RELEASE_8;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
//        return super.getSupportedAnnotationTypes();

        LinkedHashSet<String> types = new LinkedHashSet<>();
        types.add(RouteAnnotation.class.getCanonicalName());

        return types; //这个注解处理器只处理批定的注解(也就是我们自己定义的注解) 通过types.add()方法添加
    }

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

        HashMap<String, String> nameMap = new HashMap<>();

//        拿到所有RouteAnnotation注解标注的类
        Set<? extends Element> annotationElements = roundEnv.getElementsAnnotatedWith(RouteAnnotation.class);

        for (Element element : annotationElements) {

            RouteAnnotation annotation = element.getAnnotation(RouteAnnotation.class);

            String name = annotation.name();
            nameMap.put(name, element.getSimpleName().toString()); //这个集合中存了注解的name名字同时把当前页面的 类名也拿到了

        }

        //生成java文件
        generateJavaFile(nameMap);

        return true;
    }

    private void generateJavaFile(HashMap<String, String> nameMap) {

        System.out.println("执行了");

        //这是声明了一个修饰符为public的 并且有一个局部变量 routeMap 的HashMap  一个构造方法
        MethodSpec.Builder constructorBuild = MethodSpec.constructorBuilder()
                .addModifiers(Modifier.PUBLIC)
                .addStatement("routeMap = new $T<>()", HashMap.class);


        for (String key : nameMap.keySet()) {
            String name = nameMap.get(key);
            constructorBuild.addStatement("routeMap.put(\"$N\",\"$N\")", key, name); //在 构造方法中会生成 routemap.put的动作
        }

        MethodSpec constrouctName = constructorBuild.build();

        //一个普通方法
        MethodSpec reouteName = MethodSpec.methodBuilder("getActivityName")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addParameter(String.class, "routeName")
                .beginControlFlow("if(null==routeMap&&!routeMap.isEmpty())")
                .addStatement("return (String) routeMap.get(routeName)")
                .endControlFlow()
                .addStatement("return \"\"")
                .build();

        //generate class生成一个类
        TypeSpec typeSpec = TypeSpec.classBuilder("AnnotationRoute$Finder")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(constrouctName)
                .addMethod(reouteName)
                .addSuperinterface(Provider.class)
                .addField(HashMap.class, "routeMap", Modifier.PRIVATE)
                .build();

        JavaFile javaFile = JavaFile.builder("com.route.page", typeSpec).build();
        try {
            javaFile.writeTo(mFiler);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

测试生成的类是否可以调用

 * @author yulai
 * @time:
 */
@RouteAnnotation(name = "Route_MainActivity")
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new AnnotationRoute$Finder().getActivityName(""); //测试这个类生成了
    }
}

注意gradle插件和gradle的版本 先用这个版本 不要kotlin的插件使用

image.png

demo下载地址:
https://github.com/hwp2009/APT/tree/master

上一篇下一篇

猜你喜欢

热点阅读