【攻克Android (34)】Butter Knife 黄油刀

静博圣宇 2015-08-14

本文围绕以下四个部分展开:

一、注解式框架

二、ButterKnife

案例一

案例二:用ListView展示一个列表数据,每个Item里含有一个Button,可以点击。

一、注解式框架

1.注解式开发:

JDK1.5后支持注解方式。想用注解式开发,就要自定义注解。

@Override就是一种自带的注解。很多框架都采用注解方式来实现。

当追求更高的开发效率,用更简洁的代码、更清晰的代码逻辑来进行高效的开发的时候,使用注解式框架开发可简化代码提升开发效率代码的可读性

【攻克Android (34)】Butter Knife 黄油刀

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绑定问题。

案例一

【攻克Android (34)】Butter Knife 黄油刀
【攻克Android (34)】Butter Knife 黄油刀
【攻克Android (34)】Butter Knife 黄油刀
【攻克Android (34)】Butter Knife 黄油刀
【攻克Android (34)】Butter Knife 黄油刀
【攻克Android (34)】Butter Knife 黄油刀

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,可以点击。

【攻克Android (34)】Butter Knife 黄油刀
【攻克Android (34)】Butter Knife 黄油刀
【攻克Android (34)】Butter Knife 黄油刀
【攻克Android (34)】Butter Knife 黄油刀

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

相关推荐