butterknife源码解析,看完不懂你打我

首先说下butterknife原理

编译时扫描注解并通过javapoet库生成Java代码,调用ButterKnife.bind()方法将ID与对应的上下文绑定在一起(直接就说结论后面还会有人看吗少侠留步,别那么浮躁静下心来慢慢看)

butterknife是一个注解库也就是通过注解来实现View注入的,同为注解库为啥butterknife就这多Star呢,早期的注解库的生命周期是RUNTIME,在运行时通过反射来完成注入,Activity运行时大量使用反射会影响App性能同时产生很多临时对象造成gc,导致界面卡顿。而butterknife采用的是编译时解析技术,在编译时生成代码,所以对运行时没有任何影响。

在分析源码前先简单补习两点知识

元注解

元注解就是注解注解的注解,嗯!

主要有几种其中我们本次讲解用到的有@Target、@Retention。

@Target:标明了注解的使用范围,常用的有

@Retention:用来描述注解的生命周期,有三种

1)SOURCE

被编译器忽略

2)CLASS

注解将会被保留在Class文件中,但在运行时并不会被JVM保留。这是默认行为,所有没有用Retention注解的注解,都会采用这种策略。

3)RUNTIME

保留至运行时。所以我们可以通过反射去获取注解信息。

看下butterknife源码


注解处理器

注解处理器(AbstractProcessor)是javac的一个工具,利用这个工具可以在编译时扫描和处理注解,包括自定义注解,只要定义相应的注解处理器,每个注解处理器都继承AbstractProcessor类,AbstractProcessor类中有几个重要的方法

1)init(ProcessingEnvironment var1)

ProcessingEnvironment是一个接口,里面有三个重要的方法,如图

getElementUtils()方法返回一个Elements,Elements是用于处理Element的工具类,而Element由是什么呢?在注解处理过程中,扫描了所有的java源文件,我的理解是源文件抽象成类就是Element(瑟瑟发抖...不对的话请大佬指出)

Types是用于处理TypeElement的工具类,TypeElement代表源代码中的类型

Filer从文字就可以看出用于创建文件的

2)public abstract boolean process(Set var1, RoundEnvironment var2)

这个方法用于扫描和处理注解,最后会生成我们所需要的java代码,通过RoundEnvironment参数可以查到包含特定注解的原属,需要自定义处理器实现。

3)public Set getSupportedAnnotationTypes()

返回注解所支持的类型?no no no 返回所支持的注解的类型,注意这是不一样的。

4)public SourceVersion getSupportedSourceVersion()

指定所使用的java版本

需要注意的是注解处理器是运行在自己的java虚拟机中的

下面正式开始分析butterknife原理

可以看见这就是butterknife支持的注解


在process方法中会拿到所有的注解信息放到一个Map中,然后遍历Map做相应处理然后生成Java代码

findAndParseTargets(RoundEnvironment env)方法就是用于处理每一个注解的,方法很长,我们只看BindView就可以,其他逻辑一样的

看到主要逻辑都在parseBindView(Elementelement,MapbuilderMap,

SeterasedTargetNames)方法

这个方法会判断被注解的属性是不是privete或static的,如果是就会出错、包名是不是以android或java开头的,是就出错;判断注解的属性是不是一个View,不是则出错

然后int id = element.getAnnotation(BindView.class).value()获取到了要绑定的View的id,根据所在元素查找Builder,对Builder进行判断,如果已经存在了则返回else通过getOrCreateBindingBuilder(builderMap, enclosingElement)方法创建Builder,最后放到集合中

至此已经处理好注解了,下面看下如何生成java代码

在process方法中调用了brewJava方法

可以看到内部调用了createType(int sdk, boolean debuggable)来返回我们需要的类型

里面这个TypeSpec.Builder就是javapoet库构造类的属性用的类,然后就是根据各种判断来创建这个类。119行调用了createBindingConstructor(sdk, debuggable)方法,这个方法就是用于把注解转换成具体代码的,例如把@BindView换成findViewById(),有点长就不贴代码了,方法里面主要做了两件事:判断View是否有监听,如果有就声明称final的;遍历绑定的View,调用addViewBinding生成对应的findViewById方法

洋洋洒洒的把butterknife原理说完了,表达能力有限,反正也没人看就写到这吧

你可能感兴趣的:(butterknife源码解析,看完不懂你打我)