前言
学习了注解相关的知识【注解那些事儿!】,总得拿东西练练手。
运行时的处理方式看看ViewInject框架满满的够了,因为反射相关的技能以前经常使用这里就不贴了。
编译时的处理方式,当属ButterKnife框架最能体现注解处理器的作用,顺带看下其架构模式。
我所查看的是ButterKnife8.8.1的版本,因为从9.0.0开始需要minSdkVersion>=24,而10.0.0+则需要androidX。这里只是学习注解处理器相关的操作和JakeWharton设计ButterKnife的编程思想,故选此版本。
ButterKnife概览
使用
添加依赖添加依赖后便会在External Libraries看到
使用就很简单了,给控件添加注解,调用ButterKnife的bind方法,控件就赋值成功了。
查看源码
因为gradle使用了annotationProcessor,AS并不显示相关包内容
修改依赖方式,将butterknife-compiler作为一般库依赖,而非注解处理器
这时源码就出来了
源码结构
使用层面
外部调用ButterKnife.bind生成Unbinder对象,在Unbinder的构造方法内完成了注解控件的赋值。真就这么简单,以MainActivity为例
ButterKnife.bind通过查找名为“MainActivity_ViewBinding”的类,获取其构造方法生成MainActivity_ViewBinding对象,在MainActivity_ViewBinding的构造方法内对MainActivity内的控件变量进行赋值。
MainActivity_ViewBinding编译层面
入口就不是ButterKnife.bind了
-
ButterKnifeProcessor对注解进行处理,生成多个BindingSet.Builder对象
-
由BindingSet.Builder对象生成BindingSet对象(构造者模式),每一个Activity或控件容器都对应一个BindingSet对象(控件容器:Activity、Dialog、Fragment、自定义ViewGroup等)
-
由BindingSet对象生成Java代码,交由Javapoet生成Java文件,即:使用层面的Unbinder类(MainActivity_ViewBinding)
源码
ButterKnifeProcessor既然是注解处理器,关键点无外乎三处getSupportedSourceVersion、getSupportedAnnotationTypes、process,纵使源码1493行,抓住关键点,源码中实际功能也没几行
饭前甜点
真正开始前,来个小知识。
源码中这2个常量、2个变量有没有注意到,与之相关的操作是processingEnvironment.getOptions().get(),明显是获取配置信息,翻遍源码也没找到其他地方使用,因为这是gradle中配置的,用于获取配置信息
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [butterknife_minSdk: "1.0",
butterknife_debuggable: "1"]
}
}
}
这是annotationProcessor方式的配置方法,apt因为被淘汰不贴了
由于我们应用的gradle没有此配置,故变量为默认值,方便后面源码阅读
process
有了之前的基础【注解那些事儿!】这里直接进入主题。
通过findAndParseTargets获得了BindingSet对象
findAndParseTargets中最初变量是BindingSet.Builder,明显后方做了处理,找个眼熟的看看
调用了parseBindView,传入了被注解对象和集合对象
基本信息被存入BindingSet.Builder对象中
这里涉及的注解操作,可作为未来操作的样本
可见BindingSet是有包含关系的,至此BindingSet对象就生成了
接着也一目了然,由BindingSet对象生成Java代码
BindingSet & JavaPoet
这里着重强调代码编写技巧,逻辑什么的太复杂了!!
包名、注释 类名、继承关系、变量、方法 注解、修饰词、参数、静态代码段 构造函数、入参 类型写法 类型、常量、字符串写法 类型、常量、字符串写法 类型、常量、字符串写法 类型、常量、字符串写法
网友评论