转载

Android注解处理器入门

基础工程

先创建名为 AnnotationDemo 工程,如果已有工程可直接跳过:

Android注解处理器入门

注解类模块

工程内新建名为 annotation 的模块。

Android注解处理器入门

此模块存放所有注解类,示例注解类名名为 XAnnotation

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface XAnnotation {
}

因为此注解可用于修饰类,所以目标类型为: ElementType.TYPE ,并且注解信息在运行时保留。

注解处理器模块

另外新建模块 annotation_processor 用于存放注解处理器。存放注解处理器的模块必须和注解类模块分离,不然上层模块依赖后会出现问题。

Android注解处理器入门

创建之后模块布局就是这样:

Android注解处理器入门

然后,在模块里添加 javapoetkotlinpoet 依赖,推荐使用 javapoet 。还要导入上述创建的 annotation 模块,这样注解处理器就能识别我们声明的所有注解类。

apply plugin: 'java-library'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.squareup:javapoet:1.11.1'
    implementation project(":annotation")
}

sourceCompatibility = "8"
targetCompatibility = "8"

javapoet或 kotlinpoet 的功能是通过代码编写,在编译前用预设代码拼接出新的类。根据名字就知道他们分别能生成java代码和kotlin代码。

创建注解处理器:

@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"com.phantomvk.annotation.XAnnotation"})
public class XProcessor extends AbstractProcessor {

    private Filer mFiler;
    private Messager mMessager;
    private Elements mElementUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mFiler = processingEnvironment.getFiler();
        mMessager = processingEnvironment.getMessager();
        mElementUtils = processingEnvironment.getElementUtils();
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(XAnnotation.class.getCanonicalName());
        return types;
    }

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

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        // 返回false编译不会通过,必须把输入的代码输出到目标目录
        return false;
    }
}

继续完善 process() 的逻辑:

@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
    Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(XAnnotation.class);

    for (Element element : elements) {
        PackageElement packageElement = mElementUtils.getPackageOf(element);
        String packageName = packageElement.getQualifiedName().toString();

        MethodSpec methodSpec = MethodSpec.methodBuilder("showLog")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                .returns(void.class)
                .addStatement("$T.out.println($S)", System.class, "Hello JavaPoet.")
                .build();

        TypeSpec typeSpec = TypeSpec.classBuilder("XGeneratedClass")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(methodSpec)
                .build();

        JavaFile javaFile = JavaFile.builder(packageName, typeSpec)
                .build();

        try {
            javaFile.writeTo(mFiler);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return true;
}

注册上述注解处理器:

Android注解处理器入门

注册声明文件必须按照上述目录存放,而且文件名为这个:

javax.annotation.processing.Processor

文件内容的注解处理器的全路径名:

Android注解处理器入门

App导入

最后在App工程导入注解声明库和注解处理器库:

apply plugin: 'kotlin-kapt'

// JavaPoet required Java8
android {
    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }
}

dependencies {
    // ....
    implementation project(":annotation")
    kapt project(":annotation_processor") // annotationProcessor for Java
}

导入之后就可以用声明好的注解类修饰 MainActivity

@XAnnotation
class MainActivity : AppCompatActivity() {

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

点击一下构建,就会按照注解类能获取的信息生成新的类 XGeneratedClass

Android注解处理器入门

同时项目也能引用生成类:

@XAnnotation
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        XGeneratedClass.showLog() // 直接引用
    }
}

编译执行

运行之后控制台就能打印:

com.phantomvk.annotationdemo I/System.out: Hello JavaPoet.

上述文章完成声明和开发注解处理器最基本的方式,后续将在此基础上继续增强注解处理器的能力。

完整工程源码: phantomVK/AnnotationDemo

  • 上一篇

    优化应用启动内存

原文  https://phantomvk.github.io/2019/12/16/annotation_processor_startup/
正文到此结束
Loading...