首页
IT
登录
6mi
u
盘
搜
搜 索
IT
黄油刀
黄油刀
xiaoxiao
2025-09-02
230
【攻克Android (34)】Butter Knife 黄油刀
博客分类: 攻克Android系列
本文围绕以下四个部分展开:
一、注解式框架
二、Butter Knife
案例一
案例二:用 ListView 展示一个列表数据,每个Item里含有一个Button,可以点击。
一、注解式框架
1. 注解式开发:
JDK 1.5后支持注解方式。想用注解式开发,就要自定义注解。
@Override就是一种自带的注解。很多框架都采用注解方式来实现。
当追求更高的开发效率,用更简洁的代码、更清晰的代码逻辑来进行高效的开发的时候,使用注解式框架开发可简化代码,提升开发效率和代码的可读性。
2. 主流注解式框架:
(1)AndroidAnnotations
配置麻烦,需要在功能清单文件中注册生成的子类。反射机制会占用资源内存,且耗时。
(2)Dagger
采用预编译技术,高效。但是对View绑定操作注解不是很方便。
(3)Butter Knife
它是View 及事件等依赖注入框架。使用方便,配置简单,有强大的View注入绑定和简单的常用方法注解。
二、Butter Knife
它是View 及事件等依赖注入框架。
1. 特点:
(1)强大的View注入绑定和Click事件的处理。简化代码,提升开发效率。
(2)可以方便地处理ListView的Adapter里的ViewHolder绑定问题。
(3)运行时不会影响App效率,使用配置方便。
(4)代码思路清晰,可读性强。
2. 用法:
导包:
compile 'com.jakewharton:butterknife:6.0.0'
在当前 Activity(this)的onCreate中注册(注入黄油刀):
Java代码
ButterKnife.inject(
this
);
(1)View绑定(绑定控件):
Activity声明绑定控件:
Java代码
@InjectView
(R.id.tvTitle)
TextView tvTitle;
黄油刀注入控件,相当于:先声明变量,然后通过 findViewById(R.id.tvCompany) 初始化变量。黄油刀直接帮我们绑定好了控件:
InjectView: Bind a field to the view for the specified ID. The view will automatically be cast to the field type.
Java代码
@InjectView
(R.id.tvTitle)
// 相当于 通过 findViewById(R.id.tvCompany) 初始化变量。
TextView tvTitle;
// 相当于 声明变量:private TextView tvCompany;
注意:不同写为:private TextView tvTitle; 会报错:@InjectView fields must not be private or static.
(2)Onclick等事件处理:
Java代码
@OnClick
(R.id.btnHello)
public
void
sayHi(){
Toast.makeText(
this
,
"你好!"
,Toast.LENGTH_SHORT).show();
}
(3)ListView的Adapter里的ViewHolder绑定问题。
案例一
1. strings.xml。字符串。
Xml代码
<
resources
>
<
string
name
=
"app_name"
>
ButterKnifeDemo
</
string
>
<
string
name
=
"hello_world"
>
Hello world!
</
string
>
<
string
name
=
"action_settings"
>
Settings
</
string
>
<
string
name
=
"btn_good_night"
>
Good Night!
</
string
>
<
string
name
=
"btn_play"
>
播放
</
string
>
<
string
name
=
"btn_stop"
>
停止
</
string
>
<
string
name
=
"btn_view_holder"
>
ViewHolder
</
string
>
</
resources
>
2. activity_main.xml。布局
Xml代码
<
RelativeLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:paddingBottom
=
"@dimen/activity_vertical_margin"
android:paddingLeft
=
"@dimen/activity_horizontal_margin"
android:paddingRight
=
"@dimen/activity_horizontal_margin"
android:paddingTop
=
"@dimen/activity_vertical_margin"
tools:context
=
".MainActivity"
>
<
Button
android:id
=
"@+id/btnHello"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/hello_world"
/>
<
Button
android:id
=
"@+id/btnGoodNight"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_below
=
"@id/btnHello"
android:text
=
"@string/btn_good_night"
/>
<
Button
android:id
=
"@+id/btnPlay"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_below
=
"@id/btnGoodNight"
android:text
=
"@string/btn_play"
/>
<
Button
android:id
=
"@+id/btnStop"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_below
=
"@id/btnPlay"
android:text
=
"@string/btn_stop"
/>
<
Button
android:id
=
"@+id/btnViewHolder"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_below
=
"@id/btnStop"
android:text
=
"@string/btn_view_holder"
/>
</
RelativeLayout
>
3. MainActivity。View绑定和Onclick事件处理
Java代码
package
com.android.butterknifedemo;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.Menu;
import
android.view.MenuItem;
import
android.view.View;
import
android.widget.Button;
import
android.widget.Toast;
import
butterknife.ButterKnife;
import
butterknife.InjectView;
import
butterknife.OnClick;
import
butterknife.Optional;
public
class
MainActivity
extends
Activity {
// 2. Actitvity里声明绑定控件
// @Optional:加入后,若此id不存在,则程序不会崩溃,而是抛出异常
@Optional
@InjectView
(R.id.btnHello)
Button buttonHello;
@InjectView
(R.id.btnPlay)
Button buttonPlay;
@InjectView
(R.id.btnStop)
Button buttonStop;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. onCreate() 方法里注册 ButterKnife
ButterKnife.inject(
this
);
}
// 3. 注入 View 事件,不带参数
@OnClick
(R.id.btnHello)
public
void
sayHi(){
Toast.makeText(
this
,
"你好!"
,Toast.LENGTH_SHORT).show();
}
// 4. 注入 View 事件,带参数
@OnClick
(R.id.btnGoodNight)
public
void
sayGoodNight(Button btnGoodNight){
btnGoodNight.setText(
"晚上好!"
);
}
// 5. 同时注入多个 View 事件
@OnClick
({R.id.btnPlay,R.id.btnStop})
public
void
playMusic(View view){
switch
(view.getId()){
case
R.id.btnPlay:
Toast.makeText(
this
,
"播放音乐"
,Toast.LENGTH_SHORT).show();
break
;
case
R.id.btnStop:
Toast.makeText(
this
,
"停止播放"
,Toast.LENGTH_SHORT).show();
}
}
// ----------------------------------------------------------
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return
true
;
}
@Override
public
boolean
onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int
id = item.getItemId();
//noinspection SimplifiableIfStatement
if
(id == R.id.action_settings) {
return
true
;
}
return
super
.onOptionsItemSelected(item);
}
}
4. MyAdapter。处理ListView的Adapter里的ViewHolder绑定问题。
Java代码
package
com.android.butterknifedemo;
import
android.content.Context;
import
android.view.LayoutInflater;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.BaseAdapter;
import
android.widget.Button;
import
android.widget.TextView;
import
butterknife.ButterKnife;
import
butterknife.InjectView;
/**
* 在 ViewHolder 模式中注入
*/
// 1. 继承自 BaseAdapter
public
class
MyAdapter
extends
BaseAdapter{
// 4. 定义上下文
private
Context mContext;
/**
* 5. 构造方法
* @param context
*/
public
MyAdapter(Context context) {
// 上下文通过构造方法传过来
mContext = context;
}
@Override
public
int
getCount() {
return
0
;
}
@Override
public
Object getItem(
int
position) {
return
position;
}
@Override
public
long
getItemId(
int
position) {
return
0
;
}
@Override
public
View getView(
int
position, View convertView, ViewGroup parent) {
// 3. 声明 holder 为空
ViewHolder holder =
null
;
// 6.
if
(holder==
null
){
// 重新载入布局
convertView = LayoutInflater.from(mContext).inflate(
R.layout.activity_main,parent,
false
);
// 对 holder 进行实例化
holder =
new
ViewHolder(convertView);
// 获得按钮控件
holder.btnViewHolder = (Button) convertView.findViewById(R.id.btnViewHolder);
// 设置标签
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
// 7.
holder.btnViewHolder.setText(
"更改"
);
return
convertView;
}
// 2. 写一个 结构持有者 类
static
class
ViewHolder{
@InjectView
(R.id.btnViewHolder)
Button btnViewHolder;
public
ViewHolder(View view){
ButterKnife.inject(
this
,view);
}
}
}
案例二:用 ListView 展示一个列表数据,每个Item里含有一个Button,可以点击。
1. activity_main.xml。布局:一个ListView。
Xml代码
<
RelativeLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
xmlns:tools
=
"http://schemas.android.com/tools"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:paddingBottom
=
"@dimen/activity_vertical_margin"
android:paddingLeft
=
"@dimen/activity_horizontal_margin"
android:paddingRight
=
"@dimen/activity_horizontal_margin"
android:paddingTop
=
"@dimen/activity_vertical_margin"
tools:context
=
".MainActivity"
>
<
ListView
android:id
=
"@+id/listView"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
/>
</
RelativeLayout
>
2. item.xml。每一个ListView的项。包括一个文本和一个按钮
Xml代码
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
RelativeLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:descendantFocusability
=
"blocksDescendants"
android:orientation
=
"vertical"
>
<
TextView
android:id
=
"@+id/tvText"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/app_name"
/>
<
Button
android:id
=
"@+id/btn"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_toRightOf
=
"@id/tvText"
/>
</
RelativeLayout
>
注:ListView中出现button等可以拦截点击事件的控件的时候,要加属性:
Xml代码
android:descendantFocusability
=
"blocksDesendants"
3. MyAdapter。自定义适配器。
Java代码
package
com.android.bufferknifedemo;
import
android.content.Context;
import
android.view.View;
import
android.view.ViewGroup;
import
android.widget.BaseAdapter;
import
android.widget.Button;
import
android.widget.TextView;
import
android.widget.Toast;
import
java.util.ArrayList;
import
butterknife.ButterKnife;
import
butterknife.InjectView;
/**
* Created by Xiangdong on 2015/7/12.
*/
public
class
MyAdapter
extends
BaseAdapter {
Context mContext;
private
ArrayList<String> lists;
public
MyAdapter(Context context, ArrayList<String> list) {
mContext = context;
lists = list;
}
@Override
public
int
getCount() {
return
lists.size();
}
@Override
public
Object getItem(
int
position) {
return
lists.get(position);
}
@Override
public
long
getItemId(
int
position) {
return
position;
}
@Override
public
View getView(
int
position, View convertView, ViewGroup parent) {
ViewHolder holder =
null
;
if
(convertView ==
null
) {
convertView = View.inflate(mContext, R.layout.item,
null
);
holder =
new
ViewHolder(convertView);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
String s = lists.get(position);
holder.tvText.setText(s);
holder.btn.setOnClickListener(
new
View.OnClickListener() {
@Override
public
void
onClick(View v) {
Toast.makeText(mContext,
"点击"
, Toast.LENGTH_SHORT).show();
}
});
return
convertView;
}
static
class
ViewHolder {
// 绑定控件
@InjectView
(R.id.tvText)
TextView tvText;
@InjectView
(R.id.btn)
Button btn;
public
ViewHolder(View view) {
ButterKnife.inject(
this
, view);
}
}
}
4. MainActivity。
Java代码
package
com.android.bufferknifedemo;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.Menu;
import
android.view.MenuItem;
import
android.widget.ListView;
import
android.widget.Toast;
import
java.util.ArrayList;
import
butterknife.ButterKnife;
import
butterknife.InjectView;
import
butterknife.OnItemClick;
public
class
MainActivity
extends
Activity {
@InjectView
(R.id.listView)
ListView listView;
private
MyAdapter adapter;
private
ArrayList<String> list;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(
this
);
list =
new
ArrayList<>();
list.add(
"测试1"
);
list.add(
"测试2"
);
list.add(
"测试3"
);
list.add(
"测试4"
);
list.add(
"测试5"
);
list.add(
"测试6"
);
list.add(
"测试7"
);
list.add(
"测试8"
);
list.add(
"测试9"
);
adapter =
new
MyAdapter(
this
, list);
listView.setAdapter(adapter);
}
@OnItemClick
(R.id.listView)
public
void
onMyItemClick(
int
position) {
Toast.makeText(
this
,
"位置:"
+ position, Toast.LENGTH_SHORT).show();
}
// ------------------------------------------------------------------
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return
true
;
}
@Override
public
boolean
onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int
id = item.getItemId();
//noinspection SimplifiableIfStatement
if
(id == R.id.action_settings) {
return
true
;
}
return
super
.onOptionsItemSelected(item);
}
}
转载请注明原文地址: https://ju.6miu.com/read-1302238.html
最新回复
(
0
)