Android自定义注解处理器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014780554/article/details/79918633

Android自定义注解处理器

理论

相信不少开发人员在开发过程中都用到过不少的注解,它能提高我们的工作效率,也让项目和代码结构变得更简洁和清晰。目前已经有很多主流的框架也用到了注解技术。例如:ButterKnife、Dagger2、Retrofit、Glide等。可见,注解变得越来越流行了。

注解一般分为两种:运行时注解、编译时注解。

运行时注解

一般配合反射机制使用,相对编译时注解性能比较低,但是灵活性好。例如:Retrofit用的就是运行时注解。

编译时注解

编译时注解能够自动处理Java源文件,并可以根据需要生成新的文件。

今天我们就来学习一下怎么自定义一个注解处理器。关于注解的基础知识在这里我就不讲了,大家自己去学习哦。

实战

注解处理器一般通过继承AbstractProcessor类来实现,通过process方法进行处理。需要注意的是,注解处理器只能生成新的文件,不能修改已存在的源文件。

第一步:创建Java Library项目

首先我们新建一个Java Library项目,来作为注解处理器模块。注意是Java Library,不是Android Library。因为我们要用到的是javax包中的类,而Android Library中的JDK不包含这些类。
图片描述

第二步:新建自定义注解

项目创建完成后,我们就可以新建自定义注解了,这里我简单的定义了一个注解。该注解就是我们项目中需要用到的注解。


@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Template {
}

第三步:新建自定义注解处理器类

开始新建我们的自定义注解处理器。这里我新建了一个MyTemplateProcessor类,继承AbstractProcessor。

public class MyTemplateProcessor extends AbstractProcessor {

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

它必须要实现一个process方法,这个方法就相当于main函数,我们就是在这个方法中处理注解与生成新文件的。

另外还有一些其他的方法可配置,下面实现了几个常用的方法。其中@SupportedAnnotationTypes和@SupportedSourceVersion这两个注解可以代替getSupportedAnnotationTypes()和getSupportedSourceVersion()方法。


@SupportedAnnotationTypes("com.xuhj.java.processor.Template")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class MyTemplateProcessor extends AbstractProcessor {

    /**
     * 该处理器支持的所有注解类集合,在这里可以添加自定义注解
     *
     * 可以用注解@SupportedAnnotationTypes("com.xuhj.java.processor.Template")
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> set = new HashSet<>();
        // 添加自定义注解
        set.add(Template.class.getCanonicalName());
        return set;
    }

    /**
     * 该处理器支持的JDK版本,例如:SourceVersion.RELEASE_7
     * 一般返回SourceVersion.latestSupported()
     *
     * 可以用注解@SupportedSourceVersion(SourceVersion.RELEASE_7)
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    /**
     * 该初始化方法会被注解处理工具调用,并传入参数processingEnvironment,
     * 该参数提供了很多有用的工具类,例如Elements、Types、Filter等等
     */
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
    }

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

第四步:处理process()方法,并生成文件

接下来我们来写process方法中的逻辑,这里就是自动生成代码文件的地方。


    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        StringBuilder sb = new StringBuilder("package com.xuhj.java.processor;\n")
                .append("public class GeneratedTemplate{\n")
                .append("\tpublic String getMessage(){\n")
                .append("\t\treturn \"");
        for (Element element : roundEnvironment.getElementsAnnotatedWith(Template.class)) {
            String objectType = element.getSimpleName().toString();
            sb.append(objectType).append(" say hello!\\n");
        }
        sb.append("\";\n")
                .append("\t}\n")
                .append("}\n");
        try {
            JavaFileObject source = processingEnv.getFiler()
                    .createSourceFile("com.xuhj.java.processor.generated.GeneratedTemplate");
            Writer writer = source.openWriter();
            writer.write(sb.toString());
            writer.flush();
            writer.close();
        } catch (Exception e) {

        }
        return true;
    }

到这里,一个自定义注解处理器已经算是写完了,接下来就可以准备集成到项目中了。

第五步:声明自定义注解处理器

方法一:手动声明

在使用之前,我们还需要声明注解处理器。这里我们在main目录下,新建/resources/META-INF.services目录,并新建一个文件javax.annotation.processing.Processor
图片描述

在该文件中用文本声明我们的注解处理器

com.xuhj.java.processor.MyTemplateProcessor

然后执行Make Project,就可以在build目录下生成jar包了。我们可以直接拿jar包集成到项目中使用了。

方法二:自动注入

上面这种声明方式有点麻烦,想我这种懒人能偷懒就偷懒。这里用到了Google开源的AutoService库。在build.gradle中加入依赖

dependencies {
implementation ‘com.google.auto.service:auto-service:1.0-rc4’
}

然后在自定义注解处理器类中添加注解@AutoService(Processor.class)

@AutoService(Processor.class)
public class MyTemplateProcessor extends AbstractProcessor {
}

然后执行Make Project就可以和方法一一样,生成jar包。

第六步:集成到项目中

直接把生成的jar包放到项目的libs中,就可以使用了。执行Make Project,就会在build下生成我们自定义的文件。
这里写图片描述

GeneratedTemplate类就是我们代码动态生成的文件,内容如下:

package com.xuhj.java.processor;
public class GeneratedTemplate{
    public String getMessage(){
        return "MyAppGlideModule say hello!\nSampleActivity say hello!\n";
    }
}

然后就可以直接在代码中引用该类的方法了,是不是很神奇。O(∩_∩)O

遇到的问题

问题1:

这里我用的是Android studio 3.0,所以在集成到项目中的时候,编译不通过。

Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
- permissionsdispatcher-processor-2.3.1.jar
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.

解决方案:

在项目的build.gradle中添加以下


android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                includeCompileClasspath true
            }
        }
    }
}    

总结

好了,关于自定义注解处理器先讲解到这里。用注解处理器的好处就是可以自动帮我们生成一些重复大量的代码,并且能让我们的类变得干净、逻辑清晰。

猜你喜欢

转载自blog.csdn.net/u014780554/article/details/79918633