butterknife使用最多可以找到多少个控件

ButterKnife基本使用
Butter Knife处理字段和方法绑定.
重要更新: 目前(), ButterKnife的最新版本是8.0.1.
Demo项目已更新:&
以下原文是针对ButterKnife v6.1.0的, v8.0.1主要的不同在以下几个关键词:
@InjectView -& @BindView
@InjectViews -& @BindViews
ButterKnife.inject(this) -& ButterKnife.bind(this)
ButterKnife.reset(this) -&
unbinder = ButterKnife.bind(this, view);
public void onDestroyView() {
unbinder.unbind();
super.onDestroyView();
用gradle配置的时候加入:
compile 'com.jakewharton:butterknife:6.1.0'
注意是加在Module: app的gradle文件中.
加上之后不用运行什么命令,直接Sync一下就可以在External Libraries里面看到butterknife.
功能1: 再也不用写findViewById()啦.
mTextView1 = (TextView) findViewById(R.id.butter_text_view_1);
现在可以这样实现:
首先在变量声明的时候加上注解:
@InjectView(R.id.butter_text_view_2)
TextView mTextView2;
如果id找不到,会在编译的时候报错.
之后在设置好布局之后调用ButterKnife.inject():
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_butter_knife);
//using butter knife
ButterKnife.inject(this);
之后View对象就可以直接使用了.
需要注意的是View变量声明的时候不能为private或者static.
除了Activity之外,你可以提供其他的View Root,来获取对象(执行注入).
还可以用来简化Adapter里面的ViewHolder:
ButterKnife in Fragment
在Fragment中也可以使用ButterKnife来获取View:
public class SimpleFragment extends Fragment {
@InjectView(R.id.fragment_text_view)
TextView mTextV
public SimpleFragment() {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_simple, container, false);
ButterKnife.inject(this, view);
mTextView.setText("TextView in Fragment are found!");
ButterKnife in Adapter ViewHolder
Adapter有一种常用的优化策略,就是使用ViewHolder来减少findViewById()的重复调用.
以前写过相关的博文:&
用了ButterKnife之后, ViewHolder的使用可以变成这样:
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.person_item_layout, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
holder = (ViewHolder) convertView.getTag();
Person person = getItem(position);
if (null != person) {
holder.name.setText(person.getName());
holder.age.setText(String.valueOf(person.getAge()));
holder.location.setText(person.getLocation());
holder.work.setText(person.getWork());
return convertV
static class ViewHolder {
@InjectView(R.id.person_name)
@InjectView(R.id.person_age)
@InjectView(R.id.person_location)
@InjectView(R.id.person_work)
public ViewHolder(View view) {
ButterKnife.inject(this, view);
可以看到ViewHolder类加了一个带参数View的构造方法,用注解标记每个字段,再也不需要在getView()方法里调用findViewById()方法了.
功能2: 再也不用写setOnClickListener()啦.
比如之前的:
finishButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
现在可以写成:
@OnClick(R.id.basic_finish_a_button)
void finishA(View view) {
注意这里方法仍然不能是private和static, 并且可以有一个参数View,也可不写.
所有listener的参数都是optional的,可以写,也可以不写.
并且写的时候可以直接写一个具体的子类,比如参数View可以写成Button,这里的cast是自动完成的.
注意还是需要调用一下ButterKnife.inject(this);
否则事件绑定不成功.
忘记调用ButterKnife.inject(this);对于findView来说会报错,但是对于绑定事件来说不会报错,只是没有事情发生.
除了点击事件@OnClick,还有ListView的点击@OnItemClick, CheckBox的@OnCheckedChanged等等.
可以一次指定多个id,为多个View绑定一个事件处理方法,比如:
//you can bind listener to multiple views
@OnClick({R.id.button_enable, R.id.button_disable, R.id.button_alpha_0, R.id.button_alpha_1})
void editViewsClicked() {
Toast.makeText(this, "You click the Button!", Toast.LENGTH_SHORT).show();
功能3: 组建View List: 把多个View放在一起用
可以同时获取多个View,放在一个List中:
@InjectViews({R.id.label_first_name, R.id.label_middle_name, R.id.label_last_name})
List&TextView& labelV
@InjectViews({R.id.first_name, R.id.middle_name, R.id.last_name})
List&EditText& nameV&
注意id用逗号分隔,大括号包围,外面才是小括号.
apply()方法允许你为一组对象批量地设置值.
apply()方法共有3种形式:
public static &T extends View& void apply(List&T& list, Action&? super T& action)
public static &T extends View, V& void apply(List&T& list, Setter&? super T, V& setter, V value)
public static &T extends View, V& void apply(List&T& list, Property&? super T, V& setter, V value)
即Action, Setter和Property三种.
其中Action和Setter都是ButterKnife的类,需要继承,写自己的子类实现,然后传入对象.
Setter的第三个参数可以指定要set到什么值.
Property是Android中的类:
具体的使用可以参见例子:
其他实用方法
1.注入重置(Injection Rest):
可以用reset()方法将ButterKnife注入的View引用设置为null.
比如在Fragment的onCreateView()里调用ButterKnife.inject()方法注入了一些View,在onDestroyView()里想把它们置为null,可以直接调用ButterKnife.reset(this);方法.
2.选择性注入(Optional Injection):&
默认情况下,@InjectView和listener的注入都是必须的,如果target view没有被发现,则会报错.
为了抑制这种行为,可以用@Optional注解来标记field和方法,让注入变成选择性的,如果targetView存在,则注入, 不存在,则什么事情都不做.
当布局被复用时,这个@Optional注解很有用.
3.多方法的listener(Multi-method Listeners):
有一些View的listener是有多个回调方法的,比如Spinner的onItemSelectedListener:
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView&?& parent, View view, int position, long id) {
public void onNothingSelected(AdapterView&?& parent) {
方法注解可以用来绑定到这些方法中的任何一个.
每一个注解有一个默认的callback,指定它绑定到什么方法上;可以通过callback参数指定为一个特定的方法.
没有指定callback,默认对应onItemSelected()方法:
@OnItemSelected(R.id.my_spinner)
//default callback : ITEM_SELECTED
void onItemSelected(int position) {
Toast.makeText(this, "position: " + position, Toast.LENGTH_SHORT).show();
指定了callback,对应onNothingSelected()方法:
@OnItemSelected(value = R.id.my_spinner, callback = OnItemSelected.Callback.NOTHING_SELECTED)
void onNothingSelected() {
Toast.makeText(this, "Nothing", Toast.LENGTH_SHORT).show();
注意的是Spinner中只要有数据,默认都会选中第0个数据,所以想进入到onNothingSelected()方法,就需要把Adapter中的数据都清空.
具体完整例子见:
4.findById()方法
ButterKnife.findById()可以用来获取Activity,Dialog或View中的任何View.
ButterKnife自动完成了类型转换,所以获取出来以后不用进行显式强转,直接赋值给具体的View类型引用即可.
Resources:
Sample Project:
Introduction:&
Java Doc:&
阅读(...) 评论()|-Android开发相关技术(212)
|-Android第三方框架详解(28)
Hi,大家好 今天将为大家带来有关Android第三方框架的详细讲解。
ButterKnife介绍
ButterKnife是出自于的手,相信对安卓开发的人员来说,这个名字真的可以说是我们耳熟能详的了,那么对于刚刚接触Android的朋友,尤其刚刚接触ButterKnife的朋友可能不算太了解。(那么今后出去混,一定可要说认识喽)
Field and method binding for Android views which uses annotation processing to generate boilerplate code for you.
Eliminate findViewById calls by using @BindView on fields.
Group multiple views in a list or array. Operate on all of them at once with actions, setters, or properties.
Eliminate anonymous inner-classes for listeners by annotating methods with @OnClick and others.
Eliminate resource lookups by using resource annotations on fields.
class ExampleActivity extends Activity {
@BindView(R.id.user) EditT
@BindView(R.id.pass) EditT
@BindString(R.string.login_error) String loginErrorM
@OnClick(R.id.submit) void submit() {
// TODO call server…
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields…
For documentation and additional information see the website.
Remember: A butter knife is like a dagger only infinitely less sharp.
Add this to you project-level build.gradle:
buildscript {
repositories {
mavenCentral()
dependencies {
classpath ‘com.neenbedankt.gradle.plugins:android-apt:1.8’
Add this to your module-level build.gradle:
apply plugin: ‘android-apt’
dependencies {
compile ‘com.jakewharton:butterknife:8.0.1’
apt ‘com.jakewharton:butterknife-compiler:8.0.1’
Make sure the line apply plugin … is placed somewhere at the top of the file.
Snapshots of the development version are available in Sonatype’s snapshots repository.
Copyright 2013 Jake Wharton
Licensed under the Apache License, Version 2.0 (the “License”);
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
以上是引用来自这里英文简单的介绍了如何在AndroidStudio中引用依赖包,并且简单的介绍了一下使用的方法,对于英文好的朋友这些都是很简单的,但是对于那些英语不好的朋友,就显得有一些不友善了,毕竟我们是大中华。但这丝毫不能阻止我们对工具的渴求,那么接下来我将讲解黄油刀的详细介绍。
ButterKnife所用到的Java技术
在介绍前,需要大家了解一下黄油刀所用到的java知识基础。这里用到的技术为java的元注解,当然我还没有发有关于元注解的博文,因此这里的介绍就引用了,要深入了解第三方技术,请先进入了解,元注解机制。
Java标准Annotation
@Deprecated 相当于Javadoc的@deprecated,被@Deprecated标注的对象class, method等被注明为不推荐使用。主要用于javac等编译工具。
@Override 注明对象method重载了父类的方法。javac等编译工具编译时会根据此Annotation判断重载方法是否正确。
@SuppressWarnings 告诉javac等编译器忽略所指定的特定的警告信息。
@Target 被定义的annotation可以附加在那些对象上。
@Retention annotation的作用期间
@Retention 可以设置为RetentionPolicy类型的值。那么其值为
RetentionPolicy的值
RetentionPolicy.CLASS
annotation信息将被编译器编译时保存在class文件中,但执行时不会在VM装载。也就是说不能在执行时动态取得annotation信息。未设置@Retention时这将是默认设置值。
RetentionPolicy.RUNTIME
annotation信息将被编译器编译时保存在class文件中,执行时也会被VM装载。
RetentionPolicy.SOURCE
annotation信息将被编译器编译时舍弃掉。
这是我摘取的源码注解
@Target表明Annotation可以附加在哪种JAVA元素之上,可以设置为java.lang.annotation.ElementType数组类型的值。
ElementType值
ElementType.ANNOTATION_TYPE
应用于其他注解的元注解
ElementType.CONSTRUCTOR
ElementType.FIELD
ElementType.LOCAL_VARIABLE
方法中的本地变量
ElementType.METHOD
ElementType.PACKAGE
ElementType.PARAMETER
方法的参数
ElementType.TYPE
类,接口或者枚举声明
当然如果Java Annotation 不支持自定义注解的话,那我们还学习这个有什么用呢!这么好用的东西怎么可能不支持自定义呢。接下来看Annotation是如何自定义的
Annotation是一种特殊的interface。所以可以在annotation里定义方法,属性;也可以让某个类从annotation继承(implements)。
先看代码:
MyAnnotation.java
public @interface MyAnnotation{
public String value();
public String[] Values();
int number() default 0;
MyAnnotation具有一个返回String的value方法,返回String[]的Values 方法;还有一个返回int 的number方法。其中number方法具有默认值0。
TestMyAnnotation.java
class TestMyAnnotation3{
@MyAnnotation3(value = "call testMethod1 ", Values={"1 ", "2 "}, number = 1)
public void testMethod1() {
@MyAnnotation3(value = "call testMethod2 ", Values={"1 ", "2 "})
public void testMethod2() {
number具有默认值,所以标注时可以不为其赋值。其余方法则必须通过上面介绍的方法赋值。multiValues返回一个String[]数组,所以可以通过Values={“1”, “2”}为其赋值。
看到这里应该对元注解有一定理解了,那么就让我们开始介绍本篇的主角ButterKnife。
ButterKnife拆解
要想充分的理解黄油刀的逻辑思路,我们必须去啃源码,从源码中理解其工作的原理和使用的范围,以及这个第三方提供的方法有哪些。这些都是从读源码中获得的,相信看源码对你的编程技术以及逻辑上的严谨性有很大的帮助。
首先我们从ButterKnife中提供的案例来透析第三方的逻辑。Let`s go。在开始之前还是倡议大家从并建议大家结合代码跟着我一起浏览,这样效果会更加出色。
首先我们先看一下ButterKnife源码中给我们的例子,通过例子我们来从反面解析其工作原理和使用的方法。这也是我们最快理解源码的渠道(当然这里方法不止一个,找到适合自己的比任何人灌输给你的都好。)
那么就先让我们从例子的源码开始
public class SimpleActivity extends Activity {
private static final ButterKnife.Action&View& ALPHA_FADE = new ButterKnife.Action&View&() {
@Override public void apply(@NonNull View view, int index) {
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setFillBefore(true);
alphaAnimation.setDuration(500);
alphaAnimation.setStartOffset(index * 100);
view.startAnimation(alphaAnimation);
@BindView(R.id.title) TextV
@BindView(R.id.subtitle) TextV
@BindView(R.id.hello) B
@BindView(R.id.list_of_things) ListView listOfT
@BindView(R.id.footer) TextV
@BindViews({ R.id.title, R.id.subtitle, R.id.hello }) List&View& headerV
private SimpleA
@OnClick(R.id.hello) void sayHello() {
Toast.makeText(this, "Hello, views!", LENGTH_SHORT).show();
ButterKnife.apply(headerViews, ALPHA_FADE);
@OnLongClick(R.id.hello) boolean sayGetOffMe() {
Toast.makeText(this, "Let go of me!", LENGTH_SHORT).show();
return true;
@OnItemClick(R.id.list_of_things) void onItemClick(int position) {
Toast.makeText(this, "You clicked: " + adapter.getItem(position), LENGTH_SHORT).show();
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
title.setText("Butter Knife");
subtitle.setText("Field and method binding for Android views.");
footer.setText("by Jake Wharton");
hello.setText("Say Hello");
adapter = new SimpleAdapter(this);
listOfThings.setAdapter(adapter);
接下来我们一次点击进入我们感兴趣的注解,首先我们点击@BindView来看看源码是如何定义的这个接口。
这里我们看到了接口底层的定义,可以看到这个是自定义的注解,
让我们看看这个接口注解所表示的含义。
* &pre&&code&
* {@literal @}BindView(R.id.title) TextV
* &/code&&/pre&
其次我们来看看接口头部的注解含义:`@Retention(CLASS) @Target(FIELD)`这些属性值上面已经讲解了所以不再描述。
在图片中我们注意到了`@IdRes` 我们点进去查看源码,![](http:
从图片中我们可以清楚的看到这个接口中定义的注解,根据注解的类型就可以清晰知道这个接口是实现什么功能。
当然这个元注解 是实现Target规定的类型当作一个指定id的资源引用。是不是自定义起来也很简单呢,看示例源码感觉代码简介工作量突然减少了呢!那就快快加入元注解队列吧。
* 接下来介绍butterknife的使用方法。(这里需要注意在Fragment的和adapter中需要多家一个root view参数)Fragegment使用时记得同时继承onDestroyView,并在其中将ButterKnife.reset
public class FancyFragment extends Fragment {
@InjectView(R.id.button1) Button button1;
@InjectView(R.id.button2) Button button2;
@Override View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.inject(this, view);
@Override void onDestroyView() {
super.onDestroyView();
ButterKnife.reset(this);
还可以实例化控件数组,注解多一个s,也就是 InjectViews
@InjectViews({ R.id.first_name, R.id.middle_name, R.id.last_name }) List&EditText& nameViews
推荐大家使用的快速注解AS插件
首先看看如何在Android Studio上安装该插件,直接看图:
安装好后需要restart你的Android Studio。
在使用此插件前,需要已经导入了butterknife的jar(或者在build.gradle中已经加入:compile ‘com.jakewharton:butterknife:7.0.0 ’ )
随后,在你需要导入注解的Activity或者Fragment或者ViewHolder的layout资源代码上,右击,选择 Generate 然后 Generate ButterKnife Injections,这时候生成类似于下列的选择框:
Element为view的类型,ID为layout中资源的id名字,Variable Name即为你在代码中引用出来的变量名,点击Confirm后即可。
下面是Android ButterKnife Zelezny的github上的一个动态使用流程图:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:47692次
积分:1552
积分:1552
排名:第18638名
原创:79篇
转载:157篇
评论:31条
文章:10篇
阅读:3731
阅读:4179
阅读:3490
分享技术,美好生活,如果博文对你有帮助的话,
打赏支持一下吧.
如果需要帮助可以email我:
我将尽力帮助你解决Android方面技术问题.
推荐:以下都是博客老前辈.点击传送门.1537人阅读
android(13)
butterknife
让我们从繁琐的&findViewById&中解救出来。下面直接是使用方法
class ExampleActivity extends Activity {
@InjectView(R.id.title) TextV
@InjectView(R.id.subtitle) TextV
@InjectView(R.id.footer) TextV
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.inject(this);
// TODO Use &injected& views...
Fragment &销毁的时候掉用&ButterKnife.reset(this);
public class FancyFragment extends Fragment {
@InjectView(R.id.button1) Button button1;
@InjectView(R.id.button2) Button button2;
@Override View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.inject(this, view);
// TODO Use &injected& views...
& & & adapter
public class MyAdapter extends BaseAdapter {
@Override public View getView(int position, View view, ViewGroup parent) {
if (view != null) {
holder = (ViewHolder) view.getTag();
view = inflater.inflate(R.layout.whatever, parent, false);
holder = new ViewHolder(view);
view.setTag(holder);
holder.name.setText(&John Doe&);
static class ViewHolder {
@InjectView(R.id.title) TextV
@InjectView(R.id.job_title) TextView jobT
public ViewHolder(View view) {
ButterKnife.inject(this, view);
VIEW LISTS
@InjectViews({ R.id.first_name, R.id.middle_name, R.id.last_name }) List&EditText& nameV& & &&
CLICK LISTENER INJECTION
@OnClick(R.id.submit)
public void submit() {
// TODO submit data to server...
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText(&Hello!&);
}& & 还可以绑定多控件id
@OnClick({ R.id.door1, R.id.door2, R.id.door3 })
public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, &You win!&, LENGTH_SHORT).show();
Toast.makeText(this, &Try again&, LENGTH_SHORT).show();
INJECTION RESET 销毁 ButterKnife.reset(this);默认情况下&@InjectView&and&@OnClick&找到控件都是不允许为空的,否则会抛异常。可以添加&@Optional&允许为空 @Optional @InjectView(R.id.might_not_be_there) TextView mightNotBeT
@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
butterknife 在eclipse里面的配置:
点ok即可!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:20021次
排名:千里之外
原创:22篇
转载:29篇
(10)(5)(2)(3)(1)(2)(8)(1)(5)(15)安卓-csdn(87)
ButterKnife
& -- 项目地址:
都说程序员都是比较懒的,什么事情都想着让程序自动化帮忙减轻工作量,这个开源库可以让我们从大量的findViewById()和setonclicktListener()解放出来,其对性能的影响微乎其微(查看过Butter Knife的源码,其自定义注解的实现都是限定为RetentionPolicy.CLASS,也就是到编译出.class文件为止有效,在运行时不额外消耗性能,其是通过java注解自动生成java代码的形式来完成工作),其也有一个明显的缺点,那就是代码的可读性差一些,但了解了之后,上手也很快。。。
解放控件对象实例化
也就是 findViewById(),一直以来的做法都是一个个定义,然后在 setContentView() 或 inflate() 之后一一来findViewById()进行实例化,而使用 ButterKnife,你只需要在代码中 使用注解方式进行对象申明,然后在 setContentView() 或 inflate() 之后调用一句话,那么申明的所有对象自动创建出来。
@InjectView(R.id.ok_btn) //控件对应的ID
@InjectView(R.id.title_text)
TextView mTitleTextV
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
ButterKnife.inject(this);
//这样之后就可以直接使用变量了
mTitleTextView.setText(&test&);
是不是很神奇!!!
Fragment的和adapter里也可以用,不过调用时要多加一个root view参数。
Fragegment使用时记得同时继承onDestroyView,并在其中将ButterKnife.reset
1 public class FancyFragment extends Fragment {
@InjectView(R.id.button1) Button button1;
@InjectView(R.id.button2) Button button2;
@Override View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.inject(this, view);
// TODO Use &injected& views...
@Override void onDestroyView() {
super.onDestroyView();
ButterKnife.reset(this);
还可以实例化控件数组,注解多一个s,也就是&InjectViews
1 @InjectViews({ R.id.first_name, R.id.middle_name, R.id.last_name }) List&EditText& nameV
解放监听添加
如下,可以直接为 R.id.submit这个控件添加OnClickListener为submit函数,流弊啊。。。
1 @OnClick(R.id.submit)
2 public void submit() {
// TODO submit data to server...
还可以批量为多个控件添加为同一个响应函数:
1 @OnClick({ R.id.door1, R.id.door2, R.id.door3 })
public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, &You win!&, LENGTH_SHORT).show();
Toast.makeText(this, &Try again&, LENGTH_SHORT).show();
具体的可以去看该大神的项目页面。在文前已给出。
注:最新版的库已经将方法名改了,当然也是兼容上面所列的例子的。最新示例如下:
1 class ExampleActivity extends Activity {
@FindView(R.id.user) EditT
@FindView(R.id.pass) EditT
@OnClick(R.id.submit) void submit() {
// TODO call server...
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:35437次
积分:1040
积分:1040
排名:千里之外
原创:61篇
转载:48篇
评论:27条
(1)(5)(4)(5)(7)(5)(12)(12)(2)(15)(15)(26)(1)

我要回帖

更多关于 butterknife 的文章

 

随机推荐