ButterKnife源码剖析

  转载请注明:http://blog.csdn.net/chenkai19920410/article/details/51020151
  
  ButterKnife是Jake Wharton大神写开源框架。项目托管地址:
  https://github.com/JakeWharton/butterknife
  相信不少人已经非常熟悉他的使用了。网上有很多介绍其使用的文章。本文主要是想介绍一下,ButterKnife的实现原理。在阅读本文之前,可能需要先对Java注解器Annotation Processor有所了解。
  推荐文章:
  原版文章
  翻译版
  读完该文相信可以对Java Annotation Processor有了比较深入的了解。
  我们知道Spring的注解是使用Java反射机制实现的,当然如果让我们实现注解的话,可能往往也是想到利用反射来实现。但是我们知道如果通过反射,是在运行时(Runtime)来处理View的绑定等一些列事件的,这样比较耗费资源,会影响应用的性能。所以ButterKnife利用的是上文中提到的Java Annotation Processor技术,自定义了我们平时常用的一些注解,并注册相应的注解处理器,最后生成了相应的辅助类。在编译时直接通过辅助类来完成操作,这样就不会产生过多的消耗,而出现性能问题。接下来我们就一步步分析BufferKnife具体的实现。

  自定义的注解类
  ButterKnife自定义了很多我们常用的注解,@Bind,@OnClick等。看源码
  

/**
 * Bind a field to the view for the specified ID. The view will automatically be cast to the field
 * type.
 * <pre><code>
 * {@literal @}Bind(R.id.title) TextView title;
 * </code></pre>
 */
@Retention(CLASS) @Target(FIELD)
public @interface Bind {
   
  /** View ID to which the field will be bound. */
  @IdRes int[] value();
}

  通过@Target(FIELD)可以看出,该注解是使用在成员变量上的,同样的我们在看看@OnClick注解的声明:
  

/**
 * Bind a method to an {@link OnClickListener OnClickListener} on the view for each ID specified.
 * <pre><code>
 * {@literal @}OnClick(R.id.example) void onClick() {
 *   Toast.makeText(this, "Clicked!", Toast.LENGTH_SHORT).show();
 * }
 * </code></pre>
 * Any number of parameters from
 * {@link OnClickListener#onClick(android.view.View) onClick} may be used on the
 * method.
 *
 * @see OnClickListener
 */
@Target(METHOD)
@Retention(CLASS)
@ListenerClass(
    targetType = "android.view.View",
    setter = "setOnClickListener",
    type = "butterknife.internal.DebouncingOnClickListener",
    method = @ListenerMethod(
        name = "doClick",
        parameters = "android.view.View"
    )
)
public @interface OnClick {
   
  /** View IDs to which the method will be bound. */
  @IdRes int[] value() default { View.NO_ID };
}

  注解对象时方法Method,这和我们平时使用方式是吻合的。还有其他的注解,可以在源码butterknife-annotations.butterknife包下查看。
  
  ButterknifeProcessor
  有了这些注解,那么还必须实现注解处理器,ButterKnife的注解处理器是ButterKnifeProcessor类,如果有读过推荐的文章就会知道该类是继承自AbstractProcessor的。这里先简单的介绍一下AbstractProcessor。
  自定义的Processor都必须继承自AbstractProcessor,并重写process方法,不过我们往往还会重写其他的方法,如下:
  

public class TProcessor extends AbstractProcessor{
   
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        return false;
    }

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return super.getSupportedAnnotationTypes();
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return super.getSupportedSourceVersion();
    }
}

  同样的ButterKnifeProcessor主要也是实现了这几个方法。我们具体来看看:
  

private Elements elementUtils;
  private Types typeUtils;
  private Filer filer;

  @Override public synchronized void init(ProcessingEnvironment env) {
    super.init(env);

    elementUtils = env.getElementUtils();
    typeUtils = env.getTypeUtils();
    filer = env.getFiler();
  }

  @Override public Set<String> getSupportedAnnotationTypes() {
    Set<String> types = new LinkedHashSet<>();

    types.add(Bind.class.getCanonicalName());

    for (Class<? extends Annotation> listener : LISTENERS) {
      types.add(listener.getCanonicalName());
    }

    types.add(BindArray.class.getCanonicalName());
    types.add(BindBitmap.class.getCanonicalName());
    types.add(BindBool.class.getCanonicalName());
    types.add(BindColor.class.getCanonicalName());
    types.add(BindDimen.class.getCanonicalName());
    types.add(BindDrawable.class.getCanonicalName());
    types.add(BindInt.class.getCanonicalName());
    types.add(BindString.class.getCanonicalName());
    types.add(Unbinder
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值