java中的注解以及简单了解ButterKnife原理

一.先复习一下java中的注解

以Retrofit的get注解为例

   //标志注解的注解是元注解Documented,Target,Retention都是元注解
    @Documented
       //docemented是没有参数的注解,是生成javadoc的时候注解是否也生成
    @Target(METHOD)
       /*target是表明这个注解的描述的位置:

       1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
       */
    @Retention(RUNTIME)
    /*retention是指作用域

       1.SOURCE:在源文件中有效(即源文件保留)
      2.CLASS:在class文件中有效(即class保留)
       3.RUNTIME:在运行时有效(即运行时保留)
     */

    //@interface 声明为一个注解
    public @interface GET {

        //如果只有一个参数的话,名字为value() -->约定俗成,调用的时候,不用写成@GET(value="user")  @GET("users"),
        String value() default "";

       /* int age() default 18;
          float count() default 10.0;
          …………

        参数类型支持

         1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
      2.String类型
      3.Class类型
      4.enum类型
      5.Annotation类型
      6.以上所有类型的数组
        */
    }

注释可能让真相更模糊了,其实就简单几行

@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
  String value() default "";
}

根据上面的注释我们可以知道,以上的意思就是这个get注解只对方法有效,然后是运行时存在并起作用的。它有一个String类型的参数,因为只有一个参数,所以名称默认是value,可以取成别的,但是不符合规范。默认是value,然后调用的时候就可以直接写值,让代码更简洁。

@GET("users")

二.好了,现在开始ButterKnife

背景:自从java5后,加入了一个东西,就是注解处理器,什么是注解处理器,就是在编译之前你可以做一些其他的操作,比如说生成了个文件,打印个数据之类的,你想干嘛干嘛,那么本身jdk为我们提供的

AbstractProcessor类是一个抽象类

所以要继承AbstractProcessor,实现抽象方法process,而process()就是关键所在了,也就是注解处理器的入口方法了。

那么在ButterKnife中

ButterKnifeProcessor extends AbstractProcessor

已经很明显了,那么显然,一定会有process方法

@Override public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
    Map<TypeElement, BindingSet> bindingMap = findAndParseTargets(env);

    for (Map.Entry<TypeElement, BindingSet> entry : bindingMap.entrySet()) {
      TypeElement typeElement = entry.getKey();
      BindingSet binding = entry.getValue();

      JavaFile javaFile = binding.brewJava(sdk);
      try {
        javaFile.writeTo(filer);
      } catch (IOException e) {
        error(typeElement, "Unable to write binding for type %s: %s", typeElement, e.getMessage());
      }
    }

    return false;
  }

乍一看,不懂啊~~其实我一看我不懂,查阅资料之后有了一种新的方法—猜。其实也不能叫猜,大神写的代码其实很有规律,基本上都是见名知意,所以我们在看上面的代码
首先:parse
然后:遍历生成javafile,往文件里写

先一放,我们回头看butterknife在编译时其实做了一个非常重要的工作,就是生成了一个文件,比如在MainActivity中使用Bk

public class MainActivity$$ViewBinder<T extends MainActivity> implements ViewBinder<T> {
    public MainActivity$$ViewBinder() {
    }

生成了一个以$$ViewBinder为suffix的java类文件

       //…………代码省略
       view = (View)finder.findRequiredView(source, 2131427423, "field \'recyclerView\'");
        target.recyclerView = (RecyclerView)finder.castView(view, 2131427423, "field \'recyclerView\'");
        view = (View)finder.findRequiredView(source, 2131427417, "method \'turn2SimpleCustomView\'");
        view.setOnClickListener(new DebouncingOnClickListener() {
            public void doClick(View p0) {
                target.turn2SimpleCustomView();
            }
        });
        view = (View)finder.findRequiredView(source, 2131427418, "method \'turn2CustomViewGroup\'");
        view.setOnClickListener(new DebouncingOnClickListener() {
            public void doClick(View p0) {
                target.turn2CustomViewGroup();
            }
        });
        //…………代码省略

看到这里貌似跟我们以前写的findviewbyid很相似啊,其实最后调用还是finviewbyid这个方法,不然,@Bind(R.id.id)传个id干嘛,哈哈~

回到上面process的代码
先前说过

首先:parse,获取到对应的注解id的map
然后:遍历生成javafile,往文件里写,生成的文件就是以$$Viewbinder结尾的的文件,而这些文件替我们做了findviewbyid这些重复的操作。

好了,基本原理大概就是这样了,现在我们来看缺点,凡是有利有弊嘛

缺点:

  • 生成了很多隐藏文件,以$$ViewBinder结尾的类
  • 编译时要去生成文件等一系列操作,难免要增加编译时间

优点:

  • 代码简洁,已读
  • 最重要的一点就是减少开发者重复性的工作

结论:相对于Afinal这类通过反射实现注入,明显在移动端,效率更有优势,相对于运行时的效率,牺牲一点编译时的时间是值得的。

三.AndroidAnnotations和Dragger2

其实这两个框架本人并没有使用过,但是通过阅读资料得知,这个两个框架与ButterKnife是异曲同工,都是利用里比编译时通过注解处理器进行依赖的注入。有时间也会去研究一下下,^_^~~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值