【攻克Android (34)】Butter Knife 黄油刀
本文围绕以下四个部分展开:
一、注解式框架
二、ButterKnife
案例一
案例二:用ListView展示一个列表数据,每个Item里含有一个Button,可以点击。
一、注解式框架
1.注解式开发:
JDK1.5后支持注解方式。想用注解式开发,就要自定义注解。
@Override就是一种自带的注解。很多框架都采用注解方式来实现。
当追求更高的开发效率,用更简洁的代码、更清晰的代码逻辑来进行高效的开发的时候,使用注解式框架开发可简化代码,提升开发效率和代码的可读性。
2.主流注解式框架:
(1)AndroidAnnotations
配置麻烦,需要在功能清单文件中注册生成的子类。反射机制会占用资源内存,且耗时。
(2)Dagger
采用预编译技术,高效。但是对View绑定操作注解不是很方便。
(3)ButterKnife
它是View及事件等依赖注入框架。使用方便,配置简单,有强大的View注入绑定和简单的常用方法注解。
二、ButterKnife
它是View及事件等依赖注入框架。
1.特点:
(1)强大的View注入绑定和Click事件的处理。简化代码,提升开发效率。
(2)可以方便地处理ListView的Adapter里的ViewHolder绑定问题。
(3)运行时不会影响App效率,使用配置方便。
(4)代码思路清晰,可读性强。
2.用法:
导包:
compile'com.jakewharton:butterknife:6.0.0'
在当前Activity(this)的onCreate中注册(注入黄油刀):
ButterKnife.inject(this);
(1)View绑定(绑定控件):
Activity声明绑定控件:
@InjectView(R.id.tvTitle) TextView tvTitle;
黄油刀注入控件,相当于:先声明变量,然后通过findViewById(R.id.tvCompany)初始化变量。黄油刀直接帮我们绑定好了控件:
InjectView:BindafieldtotheviewforthespecifiedID.Theviewwillautomaticallybecasttothefieldtype.
@InjectView(R.id.tvTitle) // 相当于 通过 findViewById(R.id.tvCompany) 初始化变量。 TextView tvTitle; // 相当于 声明变量:private TextView tvCompany;
注意:不同写为:privateTextViewtvTitle;会报错:@InjectViewfieldsmustnotbeprivateorstatic.
(2)Onclick等事件处理:
@OnClick(R.id.btnHello) public void sayHi(){ Toast.makeText(this,"你好!",Toast.LENGTH_SHORT).show(); }
(3)ListView的Adapter里的ViewHolder绑定问题。
案例一
1.strings.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。布局
<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事件处理
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绑定问题。
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。
<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 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等可以拦截点击事件的控件的时候,要加属性:
android:descendantFocusability="blocksDesendants"
3.MyAdapter。自定义适配器。
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。
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); } }
整理时重点参考:http://www.jikexueyuan.com/course/1320.html