利用注解和apt生成模板代码(代码片段)

安卓小小鸟 安卓小小鸟     2022-12-12     743

关键词:

这里写自定义目录标题

开题

注解在很多框架中频繁的使用,比如大名鼎鼎的ButterKnife,ButterKnife运用的就是编译时注解,ButterKnife在我们编译时,就根据注解,自动生成了一些辅助类。当然还有EventBus3,也用到了注解的方法。所以,学习注解显得就尤为重要。
github地址

注解的核心方法

在介绍核心用法之前,先照例引用一些概念

@Retention 
这个注解表示注解的保留方式,有如下三种: 
SOURCE:只保留在源码中,不保留在class中,同时也不加载到虚拟机中 
CLASS:保留在源码中,同时也保留到class中,但是不加载到虚拟机中 
RUNING:保留到源码中,同时也保留到class中,最后加载到虚拟机中

@Target 
这个注解表示注解的作用范围,主要有如下:
ElementType.FIELD 注解作用于变量
ElementType.METHOD 注解作用于方法
ElementType.PARAMETER 注解作用于参数
ElementType.CONSTRUCTOR 注解作用于构造方法
ElementType.LOCAL_VARIABLE 注解作用于局部变量
ElementType.PACKAGE 注解作用于包
由于该例子只用到这几个元注解,所以只需要了解这两个即可,其他自行查询资料。

在我理解看来,注解的核心使用方法就三个

  1. 自定义注解 ,如
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface ViewHolder 
     String layoutPath();
     String ViewHolderName();
     String packageName();

  1. 获取注解 如 :
    Test.class.getAnnotation(ViewHolder.class)
    或者xxx.getAnnotation(ViewHolder.class)

  2. 获取注解值 如:
    ViewHolder holder = XXX.getAnnotation(ViewHolder.class) ;
    String layoutPath = holder.layoutPath()

能拿到值,我们的成功之路就走了80%,只要有值,我们就能干我们想干的事情。

APT

APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。
Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。
在编译初期,我们想利用注解的值做处理的时候,就用到了这个技术,或者工具。

JavaPoet

又是大神JakeWharton开源的一款快速代码生成工具,可使用API 快速生成.java文件,与APT绝配
JavaPoet github地址

有了这三样工具,我们就可以让计算机帮我们实现一些模板代码或者口水代码,比如ViewHolder。

为什么要写这么一套代码?

  1. 学习,毕竟注解很重要,APT也很重要,学无止境
  2. 懒,虽然butterKnife可以帮我们很快的绑定 事件以及view,可是我还是觉得繁琐,我觉得直接写完布局后一键生成所需代码最简单粗暴。当然有as插件帮你写butterKnife。
  3. 还是为了学习,写这套代码我自己都不一定会用,而且很多AS插件支持一键生成代码,比如:Android code Generator 。
    废话不多说,我们开始demo之路。

apt-annotaition

在一个新的Android工程新建后,我们在项目上右击,新建Module,选择JavaLibrary.

起名为 apt-annotaition,用来存放我们的自定义注解。
然后在该library的 build.gradle 中增加如下代码

apply plugin: 'java-library'
dependencies 
    implementation fileTree(dir: 'libs', include: ['*.jar'])

sourceCompatibility = "1.8"
targetCompatibility = "1.8"

apt-processor

重复上一遍操作,新建javaLibrary ,然后起名为apt-processor,这个就是我们的核心代码存放库,用来处理我们的注解,生成.java模板代码的地方。这个library要依赖于apt-annotaition
build.gradle文件做如下处理:

apply plugin: 'java-library'
dependencies 
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.auto.service:auto-service:1.0-rc2'
    implementation 'com.squareup:javapoet:1.11.1'
    implementation project(':apt-annotation')


sourceCompatibility = "1.8"
targetCompatibility = "1.8"

其中implementation 'com.google.auto.service:auto-service:1.0-rc2' 是谷歌爸爸的一个库,引用网上一段说法就是

**介绍下依赖库auto-service
在使用注解处理器需要先声明,步骤:
1、需要在 processors 库的 main 目录下新建 resources 资源文件夹;
2、在 resources文件夹下建立 META-INF/services 目录文件夹;
3、在 META-INF/services 目录文件夹下创建 javax.annotation.processing.Processor 文件;
4、在 javax.annotation.processing.Processor 文件写入注解处理器的全称,包括包路径;)
这样声明下来也太麻烦了?这就是用引入auto-service的原因。
通过auto-service中的@AutoService可以自动生成AutoService注解处理器是Google开发的,用来生成 META-INF/services/javax.annotation.processing.Processor 文件的**
 implementation 'com.squareup:javapoet:1.11.1'

是javaPoet,帮助我们生成.java文件。
到这里,我们的准备工作基本完工。
但是别忘了app的build.gradle配置

app的build.gradle

配置如下,不用完全相同,主要是标注部分,要依赖于 apt-processor apt-annotaition

至此,准备工作完毕。

自定义我们的注解ViewHolder

在定义之前,我们要先想一下我们的需求需要哪些参数,因为涉及到布局文件,所以我肯定需要文件的路径,以便我们解析,除此之外,我还要一个名字参数,用来给ViewHolder起名字。
另外,我们还需要包名,这个是后续开发过程中才想到的,因为我们在findViewById的时候引入R包需要包名。
基本上就这三个参数,想明白了,就动手吧
apt-annotaition中新建一个class 文件,代码如下

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface ViewHolder 
     String layoutPath();
     String ViewHolderName();
     String packageName();

创建核心代码 ViewHolderProcessor

apt-processor中新建类,继承自AbstractProcessor,复写相关方法

public Set<String> getSupportedAnnotationTypes()
支持的注解类型

由于我们只定义了ViewHolder类型,这里返回 ViewHolder类型的set集合即可

 public SourceVersion getSupportedSourceVersion()

支持的源码版本,写死return SourceVersion.latestSupported()即可

public synchronized void init(ProcessingEnvironment processingEnvironment)

初始化方法,用来获取一些必要参数,这里只用到了filer,mMessager
代码如下

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

mFiler 你可以理解为时文件写入
mMessager 可以理解为logcat;

public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment)

是我们处理注解的核心方法,在这里我们将获取到注解的类型和值。来生成我们需要的模板代码。
具体代码可见源码。

整体架构

写这个标题,我自己都笑了,一个demo有啥架构,不过还是贴上来吧,毕竟把demo完整介绍一遍也不现实

遇到的问题

1.如果你想看mMessger打印的日志信息,可以在build选项卡中选择

网上说有message选项卡,不知道为什么我的没有

  1. R包无法导入,之前刚写完的时候没问题,但是现在突然出现了,不知道原因,另外,如果生成的模板文件如果包名和你的app包名重复,R的包更是无法导入,原因未知,所以我现在随便写了一个com包。

使用方法

在我们的实体类中,使用注解,如demo中的TestEntity
代码如下

@ViewHolder(layoutPath ="/Users/liyaodong/android_dev/Study/APT/app/src/main/res/layout/view_card_product.xml",
ViewHolderName = "MyViewHolder",
        packageName = "com.example.androidopt")
public class TestEntity 
    String title;
    String des;


这样,我们的xml布局将自动解析,并且与实体类进行绑定
并且自动绑定一些常见方法,如setText(xxx),setImageResoure(xxx),
如果有额外的方法需求,继承类AbsAndroidMethodHandler,重写

@Override
    public String generatorMethod(String varName) 
        return null;
    

即可,记得把具体类加入到AndroidMethodMapFactory工厂方法的map中,进行所有view方法的统一管理,这个map会根据view类型自动寻找适合的methodHandler类进行方法生成。
然后一键,点击锤子按钮即可

生成位置在
app—>build—>generated–>source–>apt 下面

重要类及函数

public abstract class AbsAndroidMethodHandler implements IAndroidMethodHandler

方法生成类,具体方法

@Override
    public String getPackageName() 
        return packageName;
    

    @Override
    public String getViewClassName() 
        return className;
    

    @Override
    public String generatorMethod(String varName) 
        return null;
    

    @Override
    public String generatorFindViewById(String ViewName, String idName) 
        return ViewName + " = itemView.findViewById($T.id." + idName+")";
    

具体实现类 TextViewMethodHandler ImageViewMethodHandler

mybatis-plus小技能:代码生成器(增加mapper注解和fill填充)(代码片段)

...Mapper注解2.3Fill填充seealso引言背景:为了提升开发效率,利用mybatisplusAPI读取数据库表结构生成对应的实体entity、服务service,通过模板生成映射mapper。代码生成器完善:增加Mapper注解和Fill填充Fill填充实现思路:利用元对象 查看详情

注解处理器(apt)是什么?(代码片段)

...家和我一起,在Android世界打怪升级!上一篇讲完注解,这篇咱们科普一下注解的其中一种用途——注解处理器(APT),文章会手把手的帮助大家学会APT的使用,并使用简单的例子来进行练习。一、定义... 查看详情

04注解处理器(apt)是什么?——《android打怪升级之旅》(代码片段)

...家和我一起,在Android世界打怪升级!上一篇讲完注解,这篇咱们科普一下注解的其中一种用途——注解处理器(APT),文章会手把手的帮助大家学会APT的使用。一、定义注解处理器(AnnotationProcessingTool... 查看详情

abstractprocessor:利用注解动态生成代码

按照处理时期,注解分为两种类型,一种是运行时注解,另一种是编译时注解。编译时注解的核心依赖APT(AnnotationProcessingTools)实现,对应的处理流程为:在某些代码元素上(如类型、函数、字段等)添... 查看详情

java中的apt的工作过程(代码片段)

...作过程APT即AnnotatinoProcessingTool,他的作用是处理代码中的注解,用来生成代码,换句话说,这是用代码生成代码的工具,减少boilerplate代码.我们通过一个简单的例子来简单APT的工作过程,因为本文demo不设计ide及gradle等,请注意包名及import... 查看详情

[转]利用dockerize模板为容器内应用生成配置文件和环境变量(代码片段)

【FROM】 https://blog.csdn.net/liucaihong123/article/details/51945413 首先试验一下dockerize的可用性:最近一个docker容器里面的应用启动依赖于一个配置文件cfg.json设置模板文件cfg.template.json格式如下:"debug":true,"hostname":default.Env 查看详情

android编译时注解处理apt(代码片段)

一、注解在使用Java语言开发的过程中,我们会经常看到各种各样的注解,@Override(表示方法的重写),@Deprecated(标记过时的元素方法,类或属性),@LayoutRes(表示的是布局资源),@IdRes(表示的是ID资源),@Drawa... 查看详情

android编译时注解处理apt(代码片段)

一、注解在使用Java语言开发的过程中,我们会经常看到各种各样的注解,@Override(表示方法的重写),@Deprecated(标记过时的元素方法,类或属性),@LayoutRes(表示的是布局资源),@IdRes(表示的是ID资源),@Drawa... 查看详情

asm(代码片段)

...关系?分别解释下这几个名词APT:APT(AnnotationProcessingTool)即注解处理器,是一种处理注解的工具,确切的说它是javac的一个工具,它用来在编译时扫描和处理注解。注解处理器以Java代码(或者编译过的字节码)作为输入,生成.java文... 查看详情

酷易物联-arduino-sdk教程利用自动生成的sdk模板点灯和上传数据(代码片段)

目前更新了SDK生成代码功能,很适合新手入门,特别推荐。工作准备:开发板:ESP8266开发环境:ESP-8266arduino环境arduino软件安装接入设备:选择模板,点灯,其他随意接入设备后,进入设备控制-代码窗口直接下载代... 查看详情

如何用apt(annotationprocessingtool)自动生成代码(代码片段)

我们很多人都写过代码自动生成的工具,比如用python结合moko模板引擎,或者java结合freemarker模板引擎,protoc等,实现解析策划数据类,proto协议类,或者数据库层的实体类。大大节省了我们开发的时间,让我... 查看详情

如何用apt(annotationprocessingtool)自动生成代码(代码片段)

我们很多人都写过代码自动生成的工具,比如用python结合moko模板引擎,或者java结合freemarker模板引擎,protoc等,实现解析策划数据类,proto协议类,或者数据库层的实体类。大大节省了我们开发的时间,让我... 查看详情

apt:comment(注释工具)(代码片段)

...的主要作用是将类注释扫描到文档中。通过在类中添加类注解@Comment,在项目编译的时候,生成.java和.html文档。.java和.html文档会把一个包下的每个类具有的方法汇聚到一起,帮助开发人员一览项目API。导入工具Java... 查看详情

性能碾压poi!利用模板语法快速生成excel报表(代码片段)

...葡萄城技术公开课,将由我来为大家带来《性能碾压POI!利用模板语法快速生成Excel报表》的技术分享。本期课程,我们将借助服务端表格组件GcExcel的模板语法来完成Excel报表的生成,通过使用简单的语法标记,可以在不借助任... 查看详情

什么是注解?(代码片段)

...高的编码效率。二、作用提供信息给编译器:编译器可以利用注解来探测错误和警告信息,如@Override、@Deprecated。编译阶段时的处理:软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理,如@Param、@Return、@S... 查看详情

使用apt开发组件化框架的若干细节问题(代码片段)

...化的启动任务调度工具的使用APT实现了组件化扫描并发现注解。但是之前的文章并没有详细介绍APT如何加载到指定的生成类。这里存在一些细节问题,我详细说明下。1.1如何避免生成的类冲突首先,当我们为使用了注解... 查看详情

java中的屠龙之术:如何方便快捷地生成.class文件(代码片段)

...性所在。接下来就让我们看看它的使用方法把。0x00概述注解系列注解基础JavaPoet编译期注解处理之APT上一篇限于篇幅只介绍了APT,这篇来继续介绍javapoet,是square公司的开源库。正如其名,java诗人,通过注解来生... 查看详情

aop之注解处理器apt在android中的finderview实际详解(代码片段)

...框架,比如ButterFly、eventBus、OrmLite、Retrofit等都使用注解,注解是什么呢?注解就是元数据,可以理解为属性、方法、类等的一个说明,具体详解可百度,也可移步我的另一篇注解原理详解。一下就以ButterF... 查看详情