如何实现ButterKnife

ButterKnife的原理简述

示例代码ButterKnifeProcedure

Pluggable Annotation Processing

注解处理器

Java5 中叫APT(Annotation Processing Tool),在Java6开始,规范化为 Pluggable Annotation Processing。

第一步(收集信息)

找到所有被注解的属性或者方法,将所有的信息收集到对应的“类数据集”中。

第二步(生成源文件)

根据每一个“类数据集”,生成对应的java源文件。由于这些文件并不是在运行时生成的,因此也无需动态编译,注解处理器运行完成之后,

编译器会处理所有的编译流程。

第三步(动态注入)

运行时动态注入,即用户常规调用的 ButterKnife.bind(activity)

这一步为了避免蹩脚的调用,使用了运行时反射,但是作者对每一个类进行了缓存,因此,不会对执行效率产生多大影响。

在最新的 ButterKnife 源码(2015.06.08)中,ButterKnife已经重构了部分方法:

ButterKnife#inject -> ButterKnife#bind

@InjectView -> @FindView

等等,具体变化可以去看官方文档,本文档后续代码使用最新版本代码演示

极简实现演示

演示代码说明

  1. 示例代码由 ButterKnife 简化而来,部分定义和实现有删改,只能绑定 Activity 中的 View 字段
  2. 为了避免引入Android平台,但是又需要更直观,所以mock了android的两个类,ActivityView
  3. 为了避免使用 Pluggable Annotation Processing 过程中的jar包要求,以及波及不必要的java文件,请使用命令行运行演示,直接运行 ./run.sh 即可查看结果
  4. 保证 CLASSPATH 中含有tools.jar

第一步(收集信息)

  1. 在每一个类中找到所有被 FindView 注解的字段

  2. 每一个需要绑定的字段信息都保存为一个 FieldViewBinding 对象,比如:

     @FindView(100)
    View vView1;
    得到:
    new FieldViewBinding(vView1, android.view.View, 100)
  3. 将字段分类,获取每一个类的“类数据集”BindingClass,比如, MainActivity 对应的 “类数据集” 如下:

     MainActivity:
    List<FieldViewBinding> fieldViewBindings = new ArrayList<FieldViewBinding>();
    fieldViewBindings.add(new FieldViewBinding(vView1, android.view.View, 100))
    fieldViewBindings.add(new FieldViewBinding(vView2, android.view.View, 200))

第二步(生成 Bind 工具类源文件)

为了便于在反射时容易实例化生成的类,每一个生成的类都实现了一个 ActivityBinder 接口,因此,根据 MainActivity “类数据集”生成的文件如下:

package sample;

import android.view.View;
import android.app.Activity;
import butterknife.ButterKnife.ActivityBinder; public class MainActivity$$ViewBinder implements ActivityBinder<sample.MainActivity> {
@Override
public void bind(sample.MainActivity target) {
View view;
view = target.findViewById(100);
target.vView1 = view; //这里要求 vView1 的访问权限为 package 级别
view = target.findViewById(200);
target.vView2 = view;
}
}

第三步(动态注入)

我们在 MainActivity 中调用 ButterKnife#bind,第一件事就是找到对应生成的 Bind 工具类,这里遵循命名规则(在对应类后增加 $$ViewBinder 后缀),直接使用动态加载并实例化:

Class<?> activityBindingClass = Class.forName(targetClass.getName() + ButterKnifeProcessor.SUFFIX);
activityBinder = (ActivityBinder) activityBindingClass.newInstance();

获得相应的 ActivityBinder 之后,使用 ActivityBinder#bind 进行绑定,与手动调用 findViewById 效果相同

运行

运行:

ButterKnifeProcedure/src$ ./run.sh

结果:

mainActivity.vView1.id = 100
mainActivity.vView2.id = 200

Android分享 Q群:315658668

【Android】如何实现ButterKnife的更多相关文章

  1. Android 注解工具 ButterKnife

    Butter Knife 是 Android 视图字段和方法绑定,使用注解处理来生成样板代码. 主要特性: 在字段使用 @FindView消除findViewById调用 使用 @FindViews在 ...

  2. Android 依赖注入 ButterKnife 基本使用

    ButterKnife 是一个快速 Android View 注入框架,开发者是Jake Wharton,简单的来说,ButterKnife 是用注解的方式替代findViewById和setXXXL ...

  3. Android学习笔记- ButterKnife 8.0注解使用介绍

    前言: App项目开发大部分时候还是以UI页面为主,这时我们需要调用大量的findViewById以及setOnClickListener等代码,控件的少的时候我们还能接受,控件多起来有时候就会有一种 ...

  4. Android注解神器 ButterKnife框架

    前言: 本人是一个只有几个月工作经验的码小渣.这是我写的第一篇博客,如有不足之处还请大家不要介意,还请大佬可以指出问题. 在这几个月的实战开发中自己也遇到了很多问题,真的是举步艰难啊!!! 在实战开发 ...

  5. Android开发学习——ButterKnife使用

    为了码代码的效率,我们有了ButterKnife;其基本使用如下步骤: 1.在Android Studio的Setting中,下载plugin 2.在整个Project的build.gradle中添加 ...

  6. android studio报butterknife错误

    Error:Execution failed for task ':shipper:javaPreCompileDebug'.> Annotation processors must be ex ...

  7. Android Studio使用butterknife库绑定控件ID注解

    在线导入butterknife的jar包 在Android-app-Open Module Settings下选中module下的app 选择Dependencies,点击右边的“+”,选择第一个:1 ...

  8. Android Study 之 初识ButterKnife(8.5.1)及简单运用

    LZ-Says:突然间不知道说什么好,祝大家编码无bug吧~ 前言 话说,Android开发的兄弟们都知道,每次初始化控件,设置对应的事件.写的那点过程多并且恶心.我们先一块回想下不堪的以前~ 那些年 ...

  9. Android Butterknife使用方法总结 IOC框架

    前言: ButterKnife是一个专注于Android系统的View注入框架,以前总是要写很多findViewById来找到View对象,有了ButterKnife可以很轻松的省去这些步骤.是大神J ...

  10. Android Butterknife(黄油刀) 使用方法总结

    前言: ButterKnife是一个专注于Android系统的View注入框架,以前总是要写很多findViewById来找到View对象,有了ButterKnife可以很轻松的省去这些步骤.是大神J ...

随机推荐

  1. TypeScript开篇:尝点新鲜和甜头

    返回TS学习总目录 快速开始 我们通过创建一个简单的web应用来开始使用TypeScript.获得TS工具的方法主要有两种,一种是通过NPM(Node包管理器),另一种是通过VS2012安装TS的插件 ...

  2. 创建一个简单的HTTP服务(自动查找未使用的端口)

    var t = new Thread(new ThreadStart(() => { HttpListener listener = new HttpListener(); var prefix ...

  3. Linux:文件解压与压缩

    文件打包与压缩 常见压缩文件格式: |文件后缀名 |说明| |.zip |zip程序打包压缩的文件| |.rar |rar程序压缩的文件| |.7z |7zip程序压缩的文件| |.tar |tar程 ...

  4. Unity3d碰撞检测中碰撞器与触发器的区别

    要产生碰撞必须为游戏对象添加刚体(Rigidbody)和碰撞器,刚体可以让物体在物理影响下运动.碰撞体是物理组件的一类,它要与刚体一起添加到游戏对象上才能触发碰撞.如果两个刚体相互撞在一起,除非两个对 ...

  5. HTML5 canvas globalCompositeOperation绘图类型讲解

    我们总是将一个图形画在另一个之上,大多数情况下,这样是不够的.比如说,它这样受制于图形的绘制顺序.不过,我们可以利用 globalCompositeOperation 属性来改变这些做法.global ...

  6. Atitit.实现反向代理(1)----url rewrite 配置and内容改写 and -绝对路径链接改写 java php

    Atitit.实现反向代理(1)----url rewrite  配置and内容改写 and -绝对路径链接改写 java php 1. 代理的实现:::普通代理and反向代理?? 1 2. url  ...

  7. 轻松了解Spring中的控制反转和依赖注入(二)

    紧接上一篇文章<轻松了解Spring中的控制反转和依赖注入>讲解了SpringIOC和DI的基本概念,这篇文章我们模拟一下SpringIOC的工作机制,使我们更加深刻的理解其中的工作. 类 ...

  8. KS8U读卡器

    凯盛读卡器KS8U 厂家:http://www.chinaiccard.com/feijiechushiduxieqi/947.html 驱动安装目录的COM目录下有网页调用的例子. 公司网站:htt ...

  9. UIScrollView offset in UINavigationController

    转:UIScrollView offset in UINavigationController 通过设置viewCtronller的 self.automaticallyAdjustsScrollVi ...

  10. html5使用FileReader上传图片

    客户端代码是网上找的,修改为.net代码. <html><head>    <meta charset="utf-8">    <titl ...