Android APT 实践

APT->Annotation Processing Tool即注解处理器,编译期处理注解进而生成代码的工具。常见框架:Butterknife、Dagger、Arouter都基于此实现。下面动手写一个。

1. New Project
2. File -> New -> New Module -> Java Library -> file name -> annotation

此module存放注解,新建注解Hello

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface Hello {
    String value();
}
3. File -> New -> New Module -> Java Library -> file name -> compiler

此module处理注解,build.gradle:

apply plugin: 'java-library'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(':annotation')
    implementation 'com.squareup:javapoet:1.11.1'
    implementation 'com.google.auto.service:auto-service:1.0-rc6'
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'
}

sourceCompatibility = "7"
targetCompatibility = "7"

依赖:

  • 既然要处理注解,需依赖存放注解的module->annotation
  • javapoet:通过builder模式以及简洁友好的api生成java文件
  • AutoService:注解 AnnotationProcessor 类,生成META-INF配置信息。
4. compiler Library 中新建 class CommonProcessor
@AutoService(Processor.class)
public class CommonProcessor extends AbstractProcessor {
    //保存生成的java文件
    private Filer filer;
    //工具类,获取java类文件
    private Elements elementUtils;

    //初始化赋值
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        filer = processingEnv.getFiler();
        elementUtils = processingEnv.getElementUtils();
    }

    //返回支持处理的注解类型
    @Override
    public Set getSupportedAnnotationTypes() {
        Set types = new LinkedHashSet<>();
        types.add(Hello.class.getName());
        return types;
    }

    //返回支持的java版本号
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
    
    @Override
    public boolean process(Set set, RoundEnvironment roundEnvironment) {
        //获取所有源码文件
        Set elements = roundEnvironment.getRootElements();
        for (Element element : elements) {
            //跳过非class
            if (!(element instanceof TypeElement)) {
                continue;
            }
            //转为class类型
            TypeElement typeElement = (TypeElement) element;
            //生成的文件类名
            String targetClassName = "Hello$" + element.getSimpleName();

            //创建方法
            MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder("hello")
                    .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                    .returns(TypeName.VOID);

            //获取类注解
            Hello typeElementAnnotation = typeElement.getAnnotation(Hello.class);
            if (typeElementAnnotation != null) {
                methodSpecBuilder.addStatement("$T.out.println($S)", System.class, "Hello, " + typeElementAnnotation.value() + "!");
            }

            //获取类中所有元素
            List members = elementUtils.getAllMembers(typeElement);
            //类中含有注解元素
            List annotationMembers = new ArrayList<>();
            for (Element member : members) {
                Hello hello = member.getAnnotation(Hello.class);
                if (hello != null) {
                    annotationMembers.add(member);
                    //方法内容
                    methodSpecBuilder.addStatement("$T.out.println($S)", System.class, "Hello, " + hello.value() + "!");
                }
            }
            if (annotationMembers.isEmpty()) {
                continue;
            }

            //创建类
            TypeSpec typeSpec = TypeSpec
                    .classBuilder(targetClassName)
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .addMethod(methodSpecBuilder.build())
                    .build();
            //创建java文件
            JavaFile javaFile = JavaFile
                    .builder("com.chenxuan.androidapt", typeSpec)
                    .build();
            try {
                //保存java类文件
                javaFile.writeTo(filer);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}

CommonProcessor.process()在其中处理注解,通过javapoet api生成java文件。

5. app module下使用注解

app build.gradle

apply plugin: 'kotlin-kapt'

dependencies {
    implementation project(':annotation')
    kapt project(':compiler')
}

kotlin项目需引入kapt插件,使用kapt替代annotationProcessor。

6. MainActivity
@Hello("MainActivity")
class MainActivity : AppCompatActivity() {
    @Hello("tag")
    lateinit var tag: String

    @Hello("onCreate")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    @Hello("onResume")
    override fun onResume() {
        super.onResume()
    }
}

build->Clean project->Rebuild project,查看生成的java文件

app->build->generated->source->kapt->debug->package->Hello$MainActivity

package com.chenxuan.androidapt;

import java.lang.System;

public final class Hello$MainActivity {
  public static void hello() {
    System.out.println("Hello, MainActivity!");
    System.out.println("Hello, tag!");
    System.out.println("Hello, onCreate!");
    System.out.println("Hello, onResume!");
  }
}

到这大家可自行实现Butterknife BindView功能

你可能感兴趣的:(Android APT 实践)