Android APT不能自动生成文件

最近学习(Annotation Processing Tool)即注解处理器,在写一个小Demo的时候。写完代码,无论怎么Build都不能自动生成所需要的文件,于是各种检查寻找问题。

添加依赖

在处理注解的Java library Module 名字为Complier,添加依赖

    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.google.auto.service:auto-service:1.0-rc5'
        implementation project(path: ':Annotation')
    }
    //中文乱码问题(错误:编码GBK不可映射字符)
tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}
sourceCompatibility = "8"
targetCompatibility = "8"

Annotation为Java library Module,很简单

@Target(ElementType.FIELD) //作用于属性上  
@Retention(RetentionPolicy.CLASS) //作用于编译期,.class 存在于apk中
public @interface BindView {
    int value();
}

还有一个Android library Module 命名为apt-lib

主要有一个类ButterKnife和一个接口ViewBinder,代码如下:
1.ButterKnife.java

public class ButterKnife {
    public static void bind(Activity activity) {
        String className = activity.getClass().getName() + "$ViewBinder";
        try {
            Class<?> aClass = Class.forName(className);
            ViewBinder viewBinder = (ViewBinder) aClass.newInstance();
            viewBinder.bind(activity);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.ViewBinder.java

public interface ViewBinder<T> {
    void bind(T t);
}

注解处理器(Complier)

里面只有一个类ButterKnifeProcessor

@AutoService(Processor.class)//加上这个注解才能去执行
public class ButterKnifeProcessor extends AbstractProcessor {
    private Elements elementUtils;  //Elements中包含用于操作的工具
    private Filer filer;        //用来创建新的源文件,class以及其他文件

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        //此方法主要是去初始化需要用到的工具
        elementUtils = processingEnvironment.getElementUtils();
        filer = processingEnvironment.getFiler();
    }


    @Override
    public Set<String> getSupportedAnnotationTypes() {
        //添加支持的注解类型
        Set<String> setTypes = new LinkedHashSet<>();
        setTypes.add(BindView.class.getCanonicalName()):
        return setTypes;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        //用哪个版本的jdk编译
        return SourceVersion.RELEASE_8;
    }

    /**
     * 注解处理器的核心方法,处理具体的注解,生成新的 Java Class文件
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        try {
            JavaFileObject fileObject = filer.createSourceFile("LuacherActivity$ViewBinder");
            //获取writer,wirter就类似一支笔,去写java文件里的每一行代码
            Writer writer = fileObject.openWriter();
            writer.write("package com.lyh.apt;\n");      //包名
            writer.write("\n");
            writer.write("import com.liyh.aptlib.ViewBinder;\n");//导包
            writer.write("\n");
            writer.write("import com.lyh.apt.LuacherActivity;\n");
            writer.write("\n");
             writer.write("import com.lyh.apt.R;\n");
            writer.write("\n");
            writer.write("public class LuacherActivity$ViewBinder implements ViewBinder<LuacherActivity> {\n");
			writer.write("    @Override\n");
			writer.write("    public void bind(LuacherActivity target) {\n");
			writer.write("        target.tvText = target.findViewById(R.id.tv_text);\n}\n");
			writer.write("}");
			//最后不要忘记关流
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}

当然目前我只是把代码写死了,真正实现可以从参数RoundEnvironment中获取到注解的类,这里只是想看下这Writer的用法。具体实现可以参考
【Android】APT https://www.jianshu.com/p/7af58e8e3e1
主要是重写init(ProcessingEnvironment processingEnvironment),getSupportedAnnotationTypes(),getSupportedSourceVersion()以及process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment)这四个方法

寻找不能自动生成文件的问题

  1. @AutoService(Processor.class),这个注解必须添加,否则注解处理器不能执行;

  2. 最后写完wirter的流没有关闭,会造成生成文件,但文件内容为空,或者不全;

  3. app Module 要添加之前的三个Library依赖,如下:

     implementation project(path: ':aptlib')
     implementation project(path: ':Annotation')
     annotationProcessor project(path: ':Complier')
    

以上我反复检查了N次,确认无误仍然不能编译生成想要看到的文件,最后找个大神请教下。
说是Android Gradle及构建版本问题,我的是3.4.1 + 5.2.1,会出现不兼容的情况,大神建议3.3.2 + 4.10.1以下都可以。
听了建议降低版本果然构建编译,新的文件生成了。

自动生成的LuacherActivity$ViewBinder类

package com.lyh.apt;

import com.lyh.aptlibViewBinder;
import com.lyh.apt.LuacherActivity;
import com.lyh.apt.R;
public class LuacherActivity$ViewBinder implements ViewBinder<LuacherActivity> {
    @Override
    public void bind(LuacherActivity target) {
        target.tvText = target.findViewById(R.id.tv_text);
    }
}

生成文件目录为:APT构建出来的文件目录

参考

https://www.jianshu.com/p/7af58e8e3e18

此篇文章仅记录问题解决方法,希望对其他人有所帮助,不要像我一样,浪费了大半个晚上,还只是做无用功。

版权声明:本文为allenli0413原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/allenli0413/article/details/90602402

智能推荐

循环

与任何程序设计语言一样Java利用条件语句与循环结构确定流程控制,一下总结一下Java中的循环语句: while do while for switch 对于golang来说: switch非常灵活。从第一个expr为true的case开始执行,如果case带有fallthrough,程序会继续执行下一条case,不会再判断下一条case的expr,如果之后的case都有fallthrough,d...

1638 统计只差一个字符的子串数目(动态规划)

1. 问题描述: 给你两个字符串 s 和 t ,请你找出 s 中的非空子串的数目,这些子串满足替换一个不同字符以后,是 t 串的子串。换言之,请你找到 s 和 t 串中恰好只有一个字符不同的子字符串对的数目。比方说, "computer" 和 "computation"...

websocket基本原理

HTTP中一个request只能有一个response。而且这个response也是被动的,不能主动发起 因此过去的服务端推送信息是通过客户端不停的轮询实现的 websocket是双向通信协议,提供了服务端主动推送信息的能力 需要客户端(浏览器)和服务端同时支持 如果经过代理的话,还需要代理支持,否则有些代理在长时间无通信时会自动切断连接 因此WS为了保证连接不被断掉,会发心跳 WebSocket...

mybatis+ehcache二级缓存

导入jar包 mapper.xml文件开启二级缓存 pojo类实现序列化接口 配置ehcache.xml 测试...

python+opencv实现图像拼接

任务 拍摄两张图片去除相同部分,拼接在一起 原图 结果 步骤 读取两张图片 使用sift检测关键点及描述因子 匹配关键点 处理并保存关键点 得到变换矩阵 图像变换并拼接 代码实现 扩展 这里对右边图像进行变换,右边变得模糊,可以修改代码对左边图像变换 这里只有两张图片拼接,可以封装实现多张图片拼接 可以修改代码实现上下图片的拼接...

猜你喜欢

python_sklearn机器学习算法系列之AdaBoost------人脸识别(PCA,决策树)

          注:在读本文之前建议读一下之前的一片文章python_sklearn机器学习算法系列之PCA(主成分分析)------人脸识别(k-NearestNeighbor,KNN)         本文主要目的是通过一个简单的小...

memmove函数与memcpy函数的模拟实现

memmove函数和memcpy函数都是在内存复制任意类型的,但是它俩也有区别。当源区域和目标区域有重复的,memmove函数会复制缓冲区重叠的部分,而memcpy相反,会报出未知错误。 下面给出两个函数的实现 首先,memmove函数。 实现的基本原理如下图。 具体代码如下: memcpy函数的实现很简单,就直接给出源代码了...

SpringFramework核心 - IOC容器的实现 - 总结

1. 概述 把Spring技术内幕第一章和第二章过了一遍,也做了一些笔记, 对IOC容器的实现有了一定皮毛理解,现在跟着源码再过一遍总结一下IOC容器的初始化,Bean的初始化的过程,做一下总结 ① IOC容器和简单工厂模式 在开始之前,先想想我们平时是怎么使用IOC容器为我们管理Bean的,假设我们要把下面的User类交给IOC容器管理 我们不想关心如何创建一个User对象实例的,仅仅在需要他的...

Python和Django的安装

个人博客导航页(点击右侧链接即可打开个人博客):大牛带你入门技术栈  一、下载并安装Python Python 官方下载地址:http://www.python.org/ftp/python/ 我们这里选择的是 Python 2.7.2 。虽然目前最新版是Python 3.2.2, 但是Django目前还不支持 Python 3.2.2。 安装步骤很简单,双击安装包开...