大飞

大飞 关注TA

挑战一切!

大飞

大飞

关注TA

挑战一切!

  •  世界的顶端
  • 混口饭吃
  • 写了333,609字

最近回复

该文章投稿至Nemo社区   Android  板块 复制链接


ButterKnife源码解读

发布于 2018/12/19 17:21 16,880浏览 0回复 5,196

一.注解基础

    元注解有:

           @Retention:注解保留的生命周

          @Target:注解对象的作用范围。

          @Inherited:Inherited标明所修饰的注解,在所作用的类上,是否可以被继承。

          @Documented:如其名,javadoc的工具文档化,一般不关心。

     @Retention:

       Retention说标明了注解被生命周期,对应RetentionPolicy的枚举,表示注解在何时生效:

  • SOURCE:只在源码中有效,编译时抛弃,如@Override不加载到虚拟机

  • CLASS:编译class文件时生效。保留在源码中,但是不加载到虚拟机。即编译时注解

  • RUNTIME:运行时才生效。保留在源码中,也加载到虚拟机。即运行时注解

   @Target

    Target标明了注解的适用范围,对应ElementType枚举,明确了注解的有效范围。

  • TYPE:类、接口、枚举、注解类型。
  • FIELD:类成员(构造方法、方法、成员变量)。
  • METHOD:方法。
  • PARAMETER:参数。
  • CONSTRUCTOR:构造器。
  • LOCAL_VARIABLE:局部变量。
  • ANNOTATION_TYPE:注解。
  • PACKAGE:包声明。
  • TYPE_PARAMETER:类型参数。
  • TYPE_USE:类型使用声明。

 @Inherited

        注解所作用的类,在继承时默认无法继承父类的注解。除非注解声明了 @Inherited。同时Inherited声明出来的注,只对类有效,对方法/属性无效。

       如下方代码,注解类@AInherited声明了Inherited ,而注解BNotInherited 没有,所在在它们的修饰下:

  • 类Child继承了父类Parent的@AInherited,不继承@BNotInherited
  • 重写的方法testOverride()不继承Parent的任何注解;
  • testNotOverride()因为没有被重写,所以注解依然生效。

二.源码分析

    ButterKnife主要是通过在编译时注解完成得,编译时注解需要生成对应java代码,实现注入。通过ButterKnife注解的类会生成一个结尾为_ViewBinding 的类,如下例子:

// Generated code from Butter Knife. Do not modify!
package com.hangzhou.h890.meihao.account.activity;

import android.support.annotation.CallSuper;
import android.support.annotation.UiThread;
import android.view.View;
import butterknife.Unbinder;
import butterknife.internal.DebouncingOnClickListener;
import butterknife.internal.Utils;
import com.hangzhou.h890.meihao.R;
import java.lang.IllegalStateException;
import java.lang.Override;

public class LoginActivity_ViewBinding<T extends LoginActivity> implements Unbinder {
protected T target;

private View view2131689659;

private View view2131689709;

private View view2131689710;

private View view2131689711;

private View view2131689712;

private View view2131689713;

@UiThread
public LoginActivity_ViewBinding(final T target, View source) {
this.target = target;

View view;
view = Utils.findRequiredView(source, R.id.iv_close, "method 'onViewClicked'");
view2131689659 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.onViewClicked(p0);
}
});
view = Utils.findRequiredView(source, R.id.bt_login, "method 'onViewClicked'");
view2131689709 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.onViewClicked(p0);
}
});
view = Utils.findRequiredView(source, R.id.tv_forget_psw, "method 'onViewClicked'");
view2131689710 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.onViewClicked(p0);
}
});
view = Utils.findRequiredView(source, R.id.tv_register, "method 'onViewClicked'");
view2131689711 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.onViewClicked(p0);
}
});
view = Utils.findRequiredView(source, R.id.iv_weichat_login, "method 'onViewClicked'");
view2131689712 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.onViewClicked(p0);
}
});
view = Utils.findRequiredView(source, R.id.tv_weichat_login, "method 'onViewClicked'");
view2131689713 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.onViewClicked(p0);
}
});
}

@Override
@CallSuper
public void unbind() {
if (this.target == null) throw new IllegalStateException("Bindings already cleared.");

view2131689659.setOnClickListener(null);
view2131689659 = null;
view2131689709.setOnClickListener(null);
view2131689709 = null;
view2131689710.setOnClickListener(null);
view2131689710 = null;
view2131689711.setOnClickListener(null);
view2131689711 = null;
view2131689712.setOnClickListener(null);
view2131689712 = null;
view2131689713.setOnClickListener(null);
view2131689713 = null;

this.target = null;
}
}

    这就是ButterKnife的注入类,当我们点击onViewClicked方法可以跳转到原始类。从这个注册类可以看出,在构造中findview找出控件,在unbind中进行置null处理,让告诉gc在合适的机会回收占用的内存 ;

  这个注入类是通过核心类注解器ButterKnifeProcessor生产的。

二.核心类ButterKnifeProcessor,继承AbstractProcessor

抽象处理器 AbstractProcessor

我们自定义的处理器需要继承这个抽象处理器。

一般我们会用到它的四个方法。

    init(ProcessingEnvironment processingEnvironment)

    里面提供了Filer等工具类。注解处理器可以用Filer类创建新文件(源文件、类文件、辅助资源文件)。由此方法创建的源文件和类文件将由管理它们的工具(javac)处理。

    getSupportedSourceVersion()

    支持JDK的版本,通常返回SourceVersion.latestSupported()。

    public Set getSupportedAnnotationTypes()

    注解处理器是注册给哪些注解使用的。

    public boolean process(annotationsannotations, RoundEnvironment roundEnv)

    核心方法,在这里你可以扫描和处理注解,并生成java文件。


TIM图片20181219171847.png

待续。。。。

点赞(1)
点了个评