博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 学习使用annotationprocessor自动生成java文件
阅读量:6514 次
发布时间:2019-06-24

本文共 4526 字,大约阅读时间需要 15 分钟。

hot3.png

最近看glide源码,发现里面有个类必须用到的,没在源码里面,居然在build/generated目录下,这里面是自动生成的Java文件,比如R文件。

奇了个怪了,通过查阅大神文章知道了原来是利用了annotationprocessor编译器,在编译期间创建的,用到这个的出名框架比如:Butter Knife、Glide  。

注意:android-apt这个插件官方已经宣布不再维护,插件gradle2.2以上的版本使用annotationprocessor,所以我们这里跟着官方走。

否则报错:

现在我们来生成一个超级简单的Java文件吧

首先创建一个安卓项目如图:

主工程build.gradle文件如下

apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.example.alex.annotationprocessordemo"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    annotationProcessor project(':Compiler')
}

接下来创建一个Java Library  Module

取好Module名字后如下图:

这里要注意,Module类型是Java Library,不要选成Android Library

编辑build.gradle后的样子如下:

apply plugin: 'java-library'

 
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    // 用于生成Java文件的库
    compile 'com.squareup:javapoet:1.7.0'
    compile 'com.google.auto.service:auto-service:1.0-rc2'
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"

上面2个库一定要的,记得加上

接下来在Compiler这个module中创建一个类MyProcessor.java

package com.example.alex.compiler;
 
import com.google.auto.service.AutoService;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeSpec;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
 
 
/**
 * @AutoService(Processor.class)
 * 这个注解不要忘了,否则无法生成Java文件
 */
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor{
 
    /**
     * 文件相关的辅助类
     */
    private Filer mFiler;
    /**
     * 元素相关的辅助类
     */
    private Elements mElementUtils;
    /**
     * 日志相关的辅助类
     */
    private Messager mMessager;
 
    /**
     * 每一个注解处理器类都必须有一个空的构造函数。
     * 然而,这里有一个特殊的init()方法,它会被注解处理工具调用,
     * 并输入ProcessingEnviroment参数。
     *
     * processingEnvironment
     */
   
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mElementUtils = processingEnv.getElementUtils();
        mMessager = processingEnv.getMessager();
        mFiler = processingEnv.getFiler();
    }
 
   
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
 
 
        // 类名和包名
        TypeSpec finderClass = TypeSpec.classBuilder("MyGeneratedClass")
                .addModifiers(Modifier.PUBLIC)
//                .addSuperinterface(ParameterizedTypeName.get(TypeUtil.INJECTOR, TypeName.get(mClassElement.asType())))
//                .addMethod(methodBuilder.build())
                .build();
 
        // 创建Java文件
        JavaFile javaFile = JavaFile.builder("com.example.alex.annotationprocessordemo", finderClass).build();
 
        try {
            javaFile.writeTo(mFiler);
        } catch (IOException e) {
            e.printStackTrace();
        }
 
 
        return true;
    }
 
    /**这个方法必须重写,否则无法生成Java文件
     * 这里必须指定,这个注解处理器是注册给哪个注解的。
     * 注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。
     * 换句话说,在这里定义你的注解处理器注册到哪些注解上。
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new LinkedHashSet<>();
        types.add(Override.class.getCanonicalName());
//        types.add(OnClick.class.getCanonicalName());
        return types;
    }
}

重要函数解说

init(ProcessingEnvironment env): 每一个注解处理器类都必须有一个空的构造函数。然而,这里有一个特殊的init()方法,它会被注解处理工具调用,并输入ProcessingEnviroment参数。ProcessingEnviroment提供很多有用的工具类Elements,Types和Filer。

public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env)这相当于每个处理器的主函数main()。在这里写扫描、评估和处理注解的代码,以及生成Java文件。输入参数RoundEnviroment,可以让查询出包含特定注解的被注解元素。

getSupportedAnnotationTypes();这里必须指定,这个注解处理器是注册给哪个注解的。注意,它的返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称。换句话说,在这里定义你的注解处理器注册到哪些注解上。 

getSupportedSourceVersion();用来指定你使用的Java版本。

这个类就是编译期注解编译器会根据它来创建Java文件,里面提示的几个必须加上的地方要注意,忘记了就创建不了文件。

到这里基本工作都完成了,现在开始rebuild吧,成与不成就在于此了

看到了吗?主工程中build/generated/source/apt/debug目录下已经有了刚才命名的MyGeneratedClass.java 

哈哈,如果生成了说明就大功告成,没生成那么再好好找下原因是不是哪不对或者缺失了,现在又可以愉快玩耍了

下面是demo链接

http://download.csdn.net/download/msn465780/10171779     点击打开链接

--------------------- 
作者:Alex老夫子 
来源:CSDN 
原文:https://blog.csdn.net/msn465780/article/details/78888668 
版权声明:本文为博主原创文章,转载请附上博文链接!

转载于:https://my.oschina.net/u/1177694/blog/3018281

你可能感兴趣的文章
Redis客户端redisson实战
查看>>
连接到 JasperReports Server
查看>>
java处理高并发高负载类网站问题
查看>>
使用C#生成随机密码(纯数字或字母)和随机卡号(数字与字母组合)
查看>>
CAS服务器端集群
查看>>
设计模式 之 访问者模式
查看>>
JAVA Collections框架
查看>>
进制转换
查看>>
ASCII码
查看>>
java常用四种排序源代码
查看>>
win7 下硬盘安装Redhat7
查看>>
Redis 分布式锁的正确实现方式
查看>>
mysqldump 备份命令使用中的一些经验总结
查看>>
Linux下MySql安装配置方法总结
查看>>
ArrayList底层实现
查看>>
【转载】Java程序设计入门 (二)
查看>>
单词最近距离
查看>>
程序猿知道英语词汇
查看>>
数据存储(两)--SAX发动机XML记忆(附Demo)
查看>>
谈谈SQL 语句的优化技术
查看>>