Annotation Processor

article/2025/10/14 14:44:49

annotationProcessor和android-apt的功能是一样的,它们是替代关系。annotationProcessor是APT工具中的一种,他是google开发的内置框架,不需要引入,可以直接在build.gradle文件中使用。android-apt是由一位开发者自己开发的apt框架,随着Android Gradle 插件 2.2 版本的发布,间接的进行了替代。

 

涉及注解相关知识:

@Retention的取值范围如下(代表注解的保留位置):

RetentionPolicy.SOURCE 表示修饰的注解只在源码中保留,编译后就被遗弃了,也就是class文件中就不存在了。
RetentionPolicy.CLASS 表示修饰的注解保留到编译后的class文件,运行时就被遗弃。比如在运行时通过反射去获取这个注解,会发现是不存在的。
RetentionPolicy.RUNTIME 表示注解一直保留到运行时。

@Target:的取值范围如下(代表注解的作用目标)

@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包

@Document:该注解可以被包含在javadoc中
@Inherited:子类可以继承父类中的该注解

三方库依赖方式:

implementation:该依赖方式所依赖的库不会传递,只会在当前module中生效。
api:该依赖方式会传递所依赖的库,当其他module依赖了该module时,可以使用该module下使用api依赖的库。

compile已过时,已被 implementation 和api 取代

当我们依赖一些第三方的库时,可能会遇到com.android.support冲突的问题,就是因为开发者使用的compile或api依赖的com.android.support包与我们本地所依赖的com.android.support包版本不一样。

一、定义注解

在工程中添加一个java library类型的module,取名annotation

Android Studio -> file -> new module -> java library

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface BindView {@IdRes int value();
}

备注:注解@IdRes 引用系统库,如果是jiavaLibrary需要单独添加引用

dependencies {implementation 'androidx.annotation:annotation:1.2.0'
}

二、定义注解处理器

新建一个module,取名为compiler,类型必须为java librar(因为有用到 javax.*下的类文件)

Android Studio -> file -> new module -> java library

新建一个类MyProcessor,这类必须继承至 AbstractProcessor

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

备注:注解处理器创建完毕后,需要创建注册目录,如果是手动创建,目录如下:

 文件里面内容为自己处理器的全路径path

 建议使用google的 AutoService,通过@AutoService注解标记一下,就可以自动完成注册动作,避免了手动创建错误,引用如下:

dependencies {//google的 AutoServiceimplementation 'com.google.auto.service:auto-service:1.0-rc2'annotationProcessor 'com.google.auto.service:auto-service:1.0-rc2'//自己的注解库implementation project(':annotation')
}

生成路径:

Processor 常用到的4个方法:

    /*** 初始化常用的工具类* @param processingEnv*/@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);filer = processingEnv.getFiler();//文件操作相关messager = processingEnv.getMessager();//日志相关elementUtils = processingEnv.getElementUtils();//元素相关}
    /*** 支持的注解类型* 也可以通过系统注解* @SupportedAnnotationTypes({"com.example.annotation.BindView"})* @return*/@Overridepublic Set<String> getSupportedAnnotationTypes() {Set<String> types = new LinkedHashSet<>();types.add(BindView.class.getCanonicalName());return types;}
    /*** 核心逻辑处理* @param annotations* @param roundEnv* @return*/@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {return true;}
    /*** 支持的java版本* 也可以通过系统注解代替* @return*/@Overridepublic SourceVersion getSupportedSourceVersion() {return SourceVersion.RELEASE_7;}

系统注解使用如下:

@SupportedSourceVersion(SourceVersion.RELEASE_7)
@SupportedAnnotationTypes({"com.example.annotation.BindView"})
@AutoService(Processor.class)
public class MyProcessor extends AbstractProcessor {}

如果需要调试传递参数:

defaultConfig {applicationId "com.example.demo0328"minSdkVersion 21targetSdkVersion 25versionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"javaCompileOptions {annotationProcessorOptions {arguments = [xxxkey: 'xxxxvlaue']}}}

注解处理器所在库获取参数:

Map<String, String> options = processingEnv.getOptions();

注解相关的api可以参考:注解与APT注解处理器技术详解 - 简书

三、新建android library:inject

public interface ViewBinder<T> {void bind(T target);
}
public class InjectView {public static void bind(Activity activity) {String className = activity.getClass().getName();try {// 得到我们生成的对应该Activity的ViewBinder类的Class对象Class<?> viewBinderClass = Class.forName(className + "$$ViewBinder");ViewBinder viewBinder = (ViewBinder) viewBinderClass.newInstance();// 绑定Activity的控件viewBinder.bind(activity);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}
}

引用如下:

api project(':annotation')

接下来开始生成代码文件了。。。

代码生成

生成java文件工具有:Filer(注解处理器自带)、JavaPoet(省去手工拼接字符串麻烦)

手工生成api如下:

private void saveFile(String pkNameQ, String content) {String pkName = pkNameQ;try {//创建java类文件JavaFileObject jfo = filer.createSourceFile(pkName + ".ViewBindId", new Element[]{});Writer writer = jfo.openWriter();writer.write(writeCode(pkName, content));writer.flush();writer.close();} catch (IOException e) {e.printStackTrace();}}private String writeCode(String pkName, String content) {StringBuilder builder = new StringBuilder();builder.append("package " + pkName + ";\n\n");builder.append("import java.io.Closeable;\n");builder.append("import java.io.IOException;\n");builder.append("import android.util.Log;\n\n");builder.append("public class ViewBindId implements Closeable { \n\n");//生成方法 1builder.append("public static void setMsg(String[] args){ \n");builder.append("for (int i = 0; i < args.length; i++) { \n");builder.append("System.out.println(\"内容\"+args[i]);");builder.append("Log.i(\"wangsen\",\"内容:\"+args[i]);");builder.append("}\n");builder.append("System.out.println(\"" + content + "\");\n");builder.append("}\n");//生成方法 2builder.append("@Override\n");builder.append("public void close() throws IOException { \n");builder.append("System.out.println(\"" + content + "close\");\n");builder.append("}\n");builder.append("}");return builder.toString();}

拼接步骤麻烦,比如说换行符、导包操作等等。

javaPoet生成java文件,api如下:

 常用的api:

  • addStatement() 方法负责分号和换行
  • beginControlFlow() + endControlFlow() 需要一起使用,提供换行符和缩进。
  • addCode() 以字符串的形式添加内
  • returns 添加返回值类型
  • .constructorBuilder() 生成构造器函数
  • .addAnnotation 添加注解
  • addSuperinterface 给类添加实现的接口
  • superclass 给类添加继承的父类
  • ClassName.bestGuess(“类全名称”) 返回ClassName对象,这里的类全名称表示的类必须要存在,会自动导入相应的包
  • ClassName.get(“包名”,”类名”) 返回ClassName对象,不检查该类是否存在
  • TypeSpec.interfaceBuilder(“HelloWorld”)生成一个HelloWorld接口
  • MethodSpec.constructorBuilder() 构造器
  • addTypeVariable(TypeVariableName.get(“T”, typeClassName)) 
    会给生成的类加上泛型

占位符

  • $L代表的是字面量
  • $S for Strings
  • $N for Names(我们自己生成的方法名或者变量名等等)
  • $T for Types

具体api使用,可以参考,感谢感谢,写的挺好的:

JavaPoet使用详解_wings专栏的博客-CSDN博客_javapoet

代码生成如下:

private void autoSaveFile(String pkName, String activityName, ClassName activityClass,String bindViewFiledName, int resId) {// 创建方法MethodSpec main = MethodSpec.methodBuilder("bind").addModifiers(Modifier.PUBLIC)//.returns(void.class).addAnnotation(Override.class).addParameter(activityClass, "target").addStatement("$T.out.println($S)", System.class, "自动创建的").addStatement("target.$L = target.findViewById($L)", bindViewFiledName, resId).build();FieldSpec fieldSpec = FieldSpec.builder(int.class,"age", Modifier.PUBLIC).build();ClassName viewBinderClass = ClassName.get("com.example.inject", "ViewBinder");// 创建类TypeSpec ViewBinder = TypeSpec.classBuilder(activityName + "$$ViewBinder")//.addModifiers(Modifier.PUBLIC, Modifier.FINAL)//.addMethod(main)//.addField(String.class, "sex", Modifier.PRIVATE)//增加成员变量.addField(fieldSpec).addSuperinterface(ParameterizedTypeName.get(viewBinderClass, activityClass)).build();//String packageName = processingEnv.getElementUtils().getPackageOf(element).getQualifiedName().toString();try {//生成java文件JavaFile javaFile = JavaFile.builder(pkName, ViewBinder)//.addFileComment(" This codes are generated automatically. Do not modify!")//.build();javaFile.writeTo(filer);} catch (IOException e) {e.printStackTrace();}}

调用如下:

public class MainActivity extends AppCompatActivity {//关键@BindView(R.id.tv01)TextView tv01;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//关键InjectView.bind(this);tv01.setText(Html.fromHtml("DD<font color='red'>注入初始化*</font>"));ViewBindId.setMsg(new String[]{"a","b","c"});ViewBinderAuto.setMsg(new String[]{"D","E","F"});try {new ViewBindId().close();} catch (Exception e) {e.printStackTrace();}}
}

切记build.gradle添加相关引用:

implementation project(':inject')
//implementation project(':annotation')
annotationProcessor project(path: ':compiler')

手写拼接可以参考:EventBus,Dragger等开源库的基本原理。自动生成参考butterknife

参考:

Android关于AutoService、Javapoet讲解 - 帅气的码农 - 博客园

源码解析getCanonicalName(), getName(), getSimpleName()的不同_正在飞翔的猫的博客-CSDN博客_getcanonicalname

implementation、api、compileOnly区别详解_XeonYu的博客-CSDN博客_compileonly implementation

深入理解编译注解(二)annotationProcessor与android-apt_珠穆朗玛小王子的博客-CSDN博客

注解与APT注解处理器技术详解 - 简书

注解入坑笔记:关于注解使用必须了解的——Annotation、AbstraceProcessor、APT_Else_Q的博客-CSDN博客

秒懂Android注解处理器(Android Annotation Processor)-蒲公英云

AbstractProcessor注解处理器_廖子尧的博客-CSDN博客_abstractprocessor

通过编译期生成代码方式实现的仿ButterKnife功能Demo


http://chatgpt.dhexx.cn/article/Wu6rpMnZ.shtml

相关文章

annotation是什么,用处,举例

1.概念&#xff1a;注解Annotation是java 1.5的新特性&#xff0c;是一种能够添加到 Java 源代码的语法元数据。类、方法、变量、参数、包都可以被注解&#xff0c;可用来将信息元数据与程序元素进行关联。Annotation 中文常译为“注解”。 2.用处&#xff1a; (1)生成文档。这…

Web大学生网页作业成品:个人博客主页 (纯HTML+CSS代码)

Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 个人博客网站 | 个人主页介绍 | 个人简介 | 个人博客设计制作 | 等网站的设计与制作 | 大学生个人HTML网页设计作品 | HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&…

vue搭建博客

使用vue2.0/3.0搭建博客&#xff0c;前端情绪员 实现原理安装nodejs和vue写项目项目打包和托管项目创建github仓库安装git托管项目到github仓库检查仓库并设置pages购买域名和解析域名修改更新项目ps(gitee搭建vue博客) 实现原理 使用vue打包出来的dist&#xff0c;把dist中的…

博客中动态图的制作

在博客中的动态图片的制作&#xff0c;可以在Android Studio里面连上手机进行视频的录制。之后用在视频的基础上用gifcam软件转化成gif动态图&#xff1a; 下载gitcam绿色版软件进行视频的处理&#xff1a; 打开GIFcam转化成gif格式的动态图&#xff1a;

手把手,从零开始搭建个人博客网站(附源码)

项目介绍 一、项目功能&#xff1a; 实现登录功能 密码数据加密 用户管理功能&#xff08;用户增删改查&#xff09; 文章管理功能&#xff08;文章增删改查&#xff09; 文章首页展示 文章评论功能&#xff08;需登录&#xff09; 首页文章展示、 用户管理、文章管理的…

HTML5+CSS编写个人博客界面

刚入门html和css&#xff0c;花了一天入门基础&#xff0c;第二天花了五六个小时完成老师布置的作业——个人博客界面&#xff0c;初学者可以进行参考编写。 注&#xff1a;里面的链接都不能点击 废话少说&#xff0c;看结果&#xff1a; 参考代码&#xff1a; microbloy.htm…

js个人博客设计大作业

视频演示&#xff1a; 大作业演示 图片看效果&#xff1a; 网站规划设计 1.结构设计 共设计3个HTML界面&#xff1a;一个登陆界面&#xff0c;一个注册界面&#xff0c;以及主页面&#xff1b; 2.内容规划 登陆界面包含logo&#xff0c;输入用户名&#xff0c;输入密码和登…

python数据可视化:使用dash给博客制作一个dashboard

项目部署在&#xff1a;https://ffzs-blog-dashboard.herokuapp.com/ 项目代码在&#xff1a;https://github.com/ffzs/dash_blog_dashboard 1.dashboard 仪表板通常提供与特定目标或业务流程相关的关键绩效指标&#xff08;KPI&#xff09;的概览。另一方面&#xff0c;“仪表…

四、登录注册页功能实现《iVX低代码/无代码个人博客制作》

注&#xff1a;iVX也有免费直播课《第八期直播课》 首先打开在线编辑器进入我们的项目&#xff1a;https://editor.ivx.cn/ 一、登录页功能实现 上一节中已经完成了登录页的页面制作&#xff0c;那么这一节就开始对应的完成登录页的功能实现。 登录页的功能实现主要是对用户…

七、文章管理页面及功能实现《iVX低代码/无代码个人博客制作》

注&#xff1a;iVX也有免费直播课《第八期直播课》 一、文章管理页页面制作 文章管理页的基本结构与首页类似&#xff0c;我们复制一个首页&#xff0c;并且重命名首页的名称为文章管理页&#xff1a; 我们接着删除如下图所框选部分内容&#xff1a; 接着重命名导航为内容…

五、文章详情页制作及跳转功能实现《iVX低代码/无代码个人博客制作》

注&#xff1a;iVX也有免费直播课《第八期直播课》 一、详情页制作 在之前的章节中&#xff0c;我们已经制作完毕了登录、注册、首页等内容&#xff0c;在这一节中&#xff0c;我们编写详情页以及详情页功能制作。 详情页页面如下&#xff1a; 详情页头部也就是一个头部栏&…

三、登录页制作《iVX低代码/无代码个人博客制作》

注&#xff1a;iVX也有免费直播课《第八期直播课》 一、登录页实现 本节需要做的登录页如下&#xff1a; 该页面我们复习可以的值&#xff0c;首先设置整个页面页面的垂直和水平对其为居中&#xff0c;随后一个容器包裹对应的登录区域&#xff0c;此时我们创建一个页面命名为…

一、首页、详情页、文章编辑页制作《iVX低代码/无代码个人博客制作》

注&#xff1a;iVX也有免费直播课《第八期直播课》 一、首页制作 首页预览如下&#xff1a; 首先在博客页创建一个相对应项目&#xff1a; 接着选择前台&#xff0c;创建一个页面&#xff0c;命名为首页&#xff1a; 接着更改当前屏幕为小屏尺寸&#xff1a; 接着我们分…

二、文章发布页制作及后台实现《iVX低代码/无代码个人博客制作》

注&#xff1a;iVX也有免费直播课《第八期直播课》 一、文章编辑页制作 当首页制作完毕后&#xff0c;需要显示内容就需要有文章数据&#xff0c;此时我们创建一个文章编辑页增加对应的数据。 那么我们创建一个页面&#xff0c;命名为文章发布页&#xff1a; 接着我们查看标…

二、博客首页完成《iVX低代码仿CSDN个人博客制作》

制作iVX 低代码项目需要进入在线IDE&#xff1a;https://editor.ivx.cn/ 一、菜单思路参考及制作 在 CSDN 首页中的菜单部分为一串横排的内容&#xff0c;并且可以进行拖动&#xff1a; 首先咱们添加一个行&#xff0c;命名为菜单&#xff1a; 接着肯定是需要设置上下的内边…

四、博客详情页完成《iVX低代码仿CSDN个人博客制作》

制作iVX 低代码项目需要进入在线IDE&#xff1a;https://editor.ivx.cn/ 一、博客详情页分析 博客详情页大体分为顶部标题、发布时间、作者信息、博文内容&#xff0c;底部的评论我们在此不必做悬浮内容&#xff0c;咱们直接放到博文之下进行显示即可&#xff1b;顶部标题需要…

博客中GIF动画超简单制作

前言: 在写博客的时候图片和视频是非常通俗易懂的,比文字表述更为清晰,有时候演示过程用动画效果更好,毕竟图片只是静态的,看不出整个过程。而录制成视频,体积大,保存发送也比较麻烦,最重要的事博客中不支持这种格式,所以制作成GIF动画,方便、占用空间又小、博客也支…

一、博客首页搭建搭建《iVX低代码仿CSDN个人博客制作》

制作iVX 低代码项目需要进入在线IDE&#xff1a;https://editor.ivx.cn/ 一、头部导航栏思路参考 首先我们可以查看CSDN的博客首页&#xff0c;从中查看一下布局&#xff1a; 在以上首页中&#xff0c;我们可以得知其顶部为一个整行&#xff0c;这个行内容左侧为一个logo&am…

《博客页面制作》教程

《博客页面制作》教程 一、《博客页面制作》第一部分 效果图&#xff1a; 参考代码&#xff1a; <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>博客制作-第一部分</title><style type"text/css"&g…

Perfetto —— 靠谱的trace利器

最近踩到的坑&#xff0c;报了一个cst的测试项fail&#xff0c;帧率不符合预期&#xff0c;对应的测项进程是android.view.cts 肯定是要抓sytrace看看了 但是&#xff0c;试了systrace和atrace去抓&#xff0c;只抓了launcher的绘制&#xff0c;并没有android.view.cts的绘制…