Android 注解框架 Butterknife的核心代码分析笔记

Posted zhangjiaofa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 注解框架 Butterknife的核心代码分析笔记相关的知识,希望对你有一定的参考价值。

ButterKnife是一个注解框架,主要是针对android平台。

逐个的来看一下Library中的代码的组织架构:

1、接口Binding  这个接口里面有一定对外的定义的方法,主要的功能就是具有可读性的注解的描述语。

2、ButterKnifeProcessor,这是一个实体类,也是ButterKnife注解框架的核心类。

2、1  首先他集成了JAVA处理注解所用到的抽象类  AbstractProcessor    

关于AbstractProcessor的主要功能的说明,做下面的截图的总结:



看一下ButterKnifeProcessor的基本常量有哪些:

    public static final String SUFFIX = "$$ViewInjector";
    public static final String ANDROID_PREFIX = "android.";
    public static final String JAVA_PREFIX = "java.";
    static final String VIEW_TYPE = "android.view.View";
    private static final String LIST_TYPE = List.class.getCanonicalName();
    private static final List<Class<? extends Annotation>> LISTENERS = Arrays.asList(//
            OnCheckedChanged.class, //
            OnClick.class, //
            OnEditorAction.class, //
            OnFocusChange.class, //
            OnItemClick.class, //
            OnItemLongClick.class, //
            OnItemSelected.class, //
            OnLongClick.class, //
            OnPageChange.class, //
            OnTextChanged.class, //
            OnTouch.class //
    );
基本可看出 是一些字符串的常量定于约束  以及观察者方法注解的class集合

再看一下ButterKnifeProcessor的基本变量有哪些:

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

这三个变量应该是对于有些人来说有些陌生,没关系,API是最好的老师:

对于Elements的基本文本描述的定义如下:

用来对程序元素进行操作的实用工具方法。

兼容性注意事项: 在将来的平台版本中可能会向此接口添加一些方法。

主要功能的截图如下:


对于Type的基本文本描述的定义是: 

首先明确一点的是Type是一个接口,目前已知实现这个接口的是Class。

Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。

对于Filter的文本描述的定义:

此接口支持通过注释处理器创建新文件。以这种方式创建的文件对于实现此接口的注释处理工具将是已知的,这比启用工具来管理它们更好。在对用来编写文件内容的Writer 或 OutputStream 调用 close 方法之后,以这种方式创建的源文件和类文件被认为将由管理它们的工具处理。有三类文件要加以区分:源文件、类文件和辅助资源文件。

基本的功能的截图如下:



3、CollectionBinding  实现了Binding的接口,顾名思义是集合的绑定的定义,其中集合,内部定义了一个枚举类,分别指向的是ARRAY与LIST

4、DebouncingOnClickListener 就是针对Android中的一般性的View多次点击,多次相应而临时处理的抽象类

5、Parameter  这个类是final类型,故是不允许对其进行继承的,

其含义的文本的描述如下:

体现了一个参数的类型一个在观察者的方法内部的位置

6、ListenerBinding  这是一个观察者的绑定,依旧实现了Binding的接口,主要要注意的就是其内部的成员变量中有一个参数的集合的列表。

7、ListenerClass  这是一个定义的注解,其修饰的类型是:

@Retention(RUNTIME) @Target(ANNOTATION_TYPE)

运行时,在class文件中可以通过反射找到,并且类型是注解,可以修饰注解

这个类的内部的定义如下:

  String targetType();

  /** Name of the setter method on the @link #targetType() target type for the listener. */
  String setter();

  /** Fully-qualified class name of the listener type. */
  String type();

  /** Enum which declares the listener callback methods. Mutually exclusive to @link #method(). */
  Class<? extends Enum<?>> callbacks() default NONE.class;

  /**
   * Method data for single-method listener callbacks. Mutually exclusive with @link #callbacks()
   * and an error to specify more than one value.
   */
  ListenerMethod[] method() default  ;

  /** Default value for @link #callbacks(). */
  enum NONE  
这个观察者的set名称  这个观察者的类型的全称  声明观察者回调的枚举  对于单个观察者的回调的方法数据  方法回调的默认的数据


8、ListenerMethod  这依旧是一个定义的注解,

修饰的类型如下:

@Retention(RUNTIME) @Target(FIELD)

这也就是说,运行时可以通过反射获取,还有这个注解是修饰成员变量的

这个注解所在的观察者的方法的应用的名称  方法的参数的集合  观察者的方法回调返回的数据的类型  


9、ViewBinding  顾名思义,Android中View的绑定  同样实现了Binding的接口

10、ViewInjection  这个类整体的描述了被注入注解的View

其中维护的成员变量大概包括了id编号、ViewBinding的集合、ListenerBinding的队列集合


11、ViewInjector  给View注入注解的主动者

先看它的成员变量:

  private final Map<Integer, ViewInjection> viewIdMap = new LinkedHashMap<Integer, ViewInjection>();
  private final Map<CollectionBinding, int[]> collectionBindings =
      new LinkedHashMap<CollectionBinding, int[]>();
  private final String classPackage;
  private final String className;
  private final String targetClass;
  private String parentInjector;

从其成员变量大致可以进行下面的归纳:

1、维护了注解Vide的ID的队列Map

2、维护了集合绑定的队列Map

3、类的包名

4、类的名称

5、目标类

6、注入的父对象

从其功能函数来看,主要可以进行下面的归纳:

1、添加View的绑定

2、添加观察者的绑定

3、添加集合的绑定

4、设置父节点注入对象

5、动态生成注解的Java文件


12、Bind 这是一个注解,

修饰类型如下:

@Retention(CLASS) @Target(FIELD)
注解会在class文件中存在,但运行时无法获取,同时修饰成员变量的类型

英文注释:Bind a field to the view for the specified ID. The view will automatically be cast to the field

绑定一个成员变量到指定的ID的View上面去,同时这个View会自动的转换成为这个成员变量的类型

内部维护了一个成员变量所绑定的ID的编号


13、BindArray BindBitmap BindBool BindColor BindDimen BindDrawable BindInt BindString

上述的注解都是隶属于同一种规则,也就是绑定一个成员变量到指定ID的类型变量上去


14、ButterKnife  

来看一下这个类的注释说明:

Field and method binding for Android views. Use this class to simplify finding views and
attaching listeners by binding them with annotations.


针对的是Android View的变量与方法的绑定。使用这个类来简化找到对应的View以及附加观察者通过将注解与它们绑定的方式。


14、1  Finder  这个是ButterKnife内部定义的一个枚举类

看一下他的注释:

 DO NOT USE: Exposed for generated code.

不要直接使用它,这个是暴露给自动生成的代码


同时可以发现,在每一个枚举的常量内部,定义了一些内部的方法:

基本上是对于  类型是View、Dialog、Activity内部如何获取View以及获取Context变量的定义


14、2 接下来看一下几种绑定的方法:

无非就是如何绑定View、Dialog、Activity

15、ImmutableList  这个类定义的是一个不可改变的集合,比一般的集合要轻量级一些。内部是用一个数组来模拟的


16、InjectView  InjectViews  对应的是  绑定成员变量到一个View 上面去 一个是单个的int  一个是int[]

17、接下来的一组又是可以进行归类的注解:


OnCheckedChanged

OnClick

OnEditorAction

OnFocusChange

OnItemClick

OnItemLongClick

OnItemSelected

OnLongClick

OnPageChange

OnTextChanged

OnTouch


之所以说上面是可以进行归类的,是因为,它们的注解修饰是一样的:

除了系统级别的

@Target(METHOD)

@Retention(CLASS)


还有两个我们在前面自定义的注解的修饰:

@ListenerClass

@ListenerMethod


在注解ListenerClass  我们可以看到基本类似如下的定义:

targetType = "android.view.View",
    setter = "setOnTouchListener",
    type = "android.view.View.OnTouchListener",
    method = @ListenerMethod(
        name = "onTouch",
        parameters = 
            "android.view.View",
            "android.view.MotionEvent"
        ,
        returnType = "boolean",
        defaultReturn = "false"
    )
对上面的代码做如下的大致的解释:

1、当前的观察者的注解所绑定的类的类型

2、设置观察者的set方法的名称

3、当前的观察者的类型

4、它的成员变量method也是一个注解, 包括响应的方法的名称,响应的方法的参数,

响应的方法的函数的回调的类型,响应的方法的函数的回调的默认数值

 







以上是关于Android 注解框架 Butterknife的核心代码分析笔记的主要内容,如果未能解决你的问题,请参考以下文章

android 进阶之注解框架搭建

android 进阶之注解框架搭建

android框架设计基础--java注解全面解析

Android注解使用之通过annotationProcessor注解生成代码实现自己的ButterKnife框架

Android 注解框架 Butterknife的核心代码分析笔记

Android 注解框架 Butterknife的核心代码分析笔记