Apt+JavaPoet,简单分析流程
背景知识
APT:Annotation Processing Tool(注解处理器)
在编译期,扫描和处理定义的注解,这些库如butterknife,dragger2,eventbus都应用了该技术。
Project结构和module的作用
app
android app,运行的app
annotation(java类型的module)
用于创建注解的module
例如:@Bind(R.id.tv)
processor(java类型的module)
在编译期间处理注解,同时会生成相应的java文件
以Butterknife为例,在build文件中,都能看到*$$ViewBinder.java文件,这里面的代码就是自动生成的
library(android类型的module)
作为app和processor生成文件的桥梁,起到沟通作用。
例如:ButterKnife.bind(activity)
主要思路(以ButterKnife为例)
创建可用的注解(自定义注解)
创建注解类文件,代码中体现:@Bind(R.id.tv)
使用processor类,在编译期扫描和处理定义的注解
-
在编译时,processor类扫描所有带注解的对象(根据annotation的@Target,存在不同的Element);
-
扫描过程中,记录所有的Element,以key:类 value:List<Element>的形式作为缓存。
key存放的类,在butterknife中就是activity/fragment。
value存放的数据集合,就是该类中使用注解的对象。
在下面的代码中,key就是MainActivity,value就是存放textView的集合。
public class MainActivity extends AppCompatActivity {
@BindView(R.id.tv) TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
...无关代码...
ButterKnife.bind(this);
}
}
- 在拿到项目中所有的@Bind后,需要做的就是绑定控件的操作。
原始的绑定操作就是:
MainActivity.textView=MainActivity.findViewById(R.id.tv)
现在,我们需要创建一个类,让该类帮我们做重复的findViewById工作。
使用JavaFileObject或是JavaPoet生成我们需要的类,我们给这个类名再加个特殊字符:$$ViewBind
,最后就变成了MainActivity$$ViewBind.java。
//MainActivity$$ViewBind.java文件
//这里都是使用JavaFileObject或JavaPoet生成的
public class MainActivity$$ViewBind implements IViewBind<MainActivity> {
@Override
public void bind(MainActivity target) {
target.textView = target.findViewById(2131165326);
}
}
library关联app和*$$ViewBind文件
- 这里的代码很简单,首先思考一个问题,我们已知了$$ViewBind的文件路径,如何生成该类?
使用反射的方式,通过Class.forName(文件路径)
方法拿到该类。
调用该类的bind方法绑定,$$ViewBind类执行绑定控件的操作。
public static void bind(Object object) {
//获取apt生成的类
try {
Class<?> clazz = Class.forName(object.getClass().getName() + "$$ViewBind");
//new apt生成的类($$ViewBind)
IViewBind targetClass = (IViewBind) clazz.newInstance();
//调用类的方法绑定($$ViewBind.bind方法)
targetClass.bind(object);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
总结
其实就三步曲:
- 找到注解对象
- 生成绑定对象的类
- app中调用桥梁,传入activity绑定控件
相关知识点:
- 反射
- Processor的使用(继承AbstractProcessor)
- JavaPoet
- 接口的理解