目录:html
一、基础知识java
三、总结github
本文是关于ButterKnife的移植的第一篇:api
先介绍基础知识,理解apt是什么,最终输出一个乞丐版BufferKnife注入工具。数组
这是读懂BufferKnife源码的基础。app
第二篇占坑:具体讲解BufferKnife的移植。框架
基础知识
apt技术的实际应用:
-
Android Databinding绑定viewide
-
ButterKnife绑定view工具
-
Dagger2注入变量
-
ARouter生成路由表
真的好多,很重要。apt就是生产力工具!
什么是apt?
通俗讲:apt就是javac对外开放的一个插件,使javac在编译期间获取注解(Annotation),并作出相应的处理(多数都是生成一些java代码)。
从上图能够看出apt处理的是 java源文件 ,在编译期介入。
与之对比的是asm之类的工具,处理的是字节码文件,在编译后期介入。
apt与javac的约定
apt与javac约定在META-INF/services/javax.annotation.processing.Processor
文件中注册apt插件。这样apt就参与到javac的编译过程当中了。
写一个乞丐版BufferKnife
不想看文字,直接看源码,点击 https://gitee.com/andych008/aptDemo
初始代码fork自 https://github.com/LiMubai2017/aptDemo ,先对做者表示感谢。
乞丐版BufferKnife做为一款view注入工具,主要干了3件事,
- 解析注解
- 处理注解(生成模板类文件)
- 经过模板类注入view对象
第0步:准备工做
先定义注解BindView
,被@BindView
标记的变量会被注入。
通常注解都定义在一个单独的module(如取名apt-annotation),由于它会被apt-compiler和apt-api都依赖,属于公共代码。
apt-compiler是apt的主要代码所在,完成注解的解析、模板文件的生成。
apt-api则是对外的工具类,供用户使用,完成注入操做。
app是demo,其中定义了
@BindView(value = ResourceTable.Id_text_helloworld) public Text testTextView;
第一步:解析注解
在apt-compiler中定义类BindViewProcessor
继承javax.annotation.processing.AbstractProcessor
,实现其中的getSupportedAnnotationTypes()
该方法注册要解析的注解。
第二步:处理注解(生成模板文件)
在BindViewProcessor
中实现process()
方法,处理注解。
先理解javax.lang.model.element.Element
和javax.lang.model.type.TypeMirror
,参考这里 有详细的解释。
简单讲:
Element是描述java语言元素的类,好比包、类、变量、参数等。
TypeMirror是描述Element类型的类,好比各类基本类型、数组、类等。
很绕,只有多用才能真正理解。好比:demo中testTextView
就是VariableElement元素类型
TypeElement enclosingElement = (TypeElement) variableElement.getEnclosingElement();//获取表明MainAbility的TypeElement String field = variableElement.getSimpleName().toString();//testTextView TypeMirror typeMirror = variableElement.asType();//ohos.agp.components.Text
经过log()
方法,可使用Messager
打日志,验证咱们的理解。
log(String.format("element : (%s) %s ", element.getKind(), element)); log(String.format("bind : (%s) %s <--> id = %d", typeMirror, field, id)); 输出日志: 注: element : (FIELD) testTextView 注: bind : (ohos.agp.components.Text) testTextView <--> id = 16777222
generateCodeByPoet()
方法中,使用javapoet生成模板代码MainAbility$$Autobind.java
(文件路径app/build/generated/source/annotation/debug/com/example/apt_demo/MainAbility$$Autobind.java
)
关于javapoet的使用,直接看官方文档吧:https://github.com/square/javapoet
解释一下下面这段代码,让你们对javapoet有一直观的认识
MethodSpec.Builder injectMethod = MethodSpec.methodBuilder("inject")//生成一个方法,方法名是inject .addAnnotation(Override.class)//给方法加上"Override.class"注解 .addModifiers(Modifier.PUBLIC)//给方法加上访问控制符 .addParameter(Object.class, "target")//给方法加上参数 .addStatement("$T substitute = ($T)target", className, className);//在方法体内定义一条语名
上面的代码生成下面的代码(我用java代码生成java代码,这就是javapoet干的事情):
@Override public void inject(Object target) { MainAbility substitute = (MainAbility)target; }
看完上面这一坨,你若是以为难。请用JavaWriter
生成java文件。你就会以为javapoet真香。
第三步:经过模板类注入view对象
在apt-api中,咱们定义一个AutoBind.java
类封装对模板类MainAbility$$Autobind.java
的操做。
按照模板类的命名规则xxx$$Autobind
,经过反射实例化出MainAbility$$Autobind.java
,调用 其中的inject方法,完成view的注入。
总结
apt只是一个工具,在这套工具框架下,怎么处理注解才是难点。
BufferKnife和咱们的“乞丐版BufferKnife”本质上没有区别。除了注入view,还支持事件绑定、增量编译。
做者:没用的喵叔
想了解更多内容,请访问51CTO和华为合做共建的鸿蒙社区:https://harmonyos.51cto.com