Android Butter Knife Example

In this android tutorial, we are going to learn how to use Android ButterKnife View Binding in android application development.

If you have been developing android application, you will realized that there are lots of boilerplate codes in your application that can get to the way of your main business logic. A good example is when you have like 20 View widgets in your layout file and to get the instances of these widgets in your Activity of Fragment class, you will call the findViewById() method 20 times.

In some cases, it will be too much that the onCreate() method will be bloated by boilerplate codes.

This is where Android Butterknife comes to your help. Before you start using it, the points below is how it can help improve your code.

  1. Eliminate findViewById calls by using @BindView on fields.
  2. Group multiple views in a list or array. Operate on all of them at once with actions, setters, or properties.
  3. Eliminate anonymous inner-classes for listeners by annotating methods with @OnClick and others.
  4. Eliminate resource lookups by using resource annotations on fields.

A typical example of instantiating a view widget using Butterknife is as shown below.

@BindView(R.id.user) EditText username;
@BindView(R.id.pass) EditText password;
@BindView(R.id.user) EditText username;
@BindView(R.id.pass) EditText password;

Another important use case of Butterknife is that it is not only made for View binding. Butterknife can as well be used to bind predefine resource in your android project. Example below shows you how it can be achieved.

@BindString(R.string.title) String title;
@BindDrawable(R.drawable.graphic) Drawable graphic;
@BindColor(R.color.red) int red; 
@BindDimen(R.dimen.spacer) Float spacer;

In addition to what we can covered, another important usage is for binding listeners. A simple example of how to bind to a Listener is shown below.

@OnClick(R.id.submit)
public void submit(View view) {
}

Butterknife works in a simply by using annotation to generate code that application will reference to when bind is called.

There are many other ways that you can use Butter knife. If you want to read more I will suggest you visit the official website here.

Using Butter Knife with Android RecyclerView

Now that we have a general idea of how to use Butter Knife and what it does. We will go ahead and see how we can use Butter Knife view bind in android recyclerview.

We will create a MainActivity class with it corresponding layout. Add a RecyclerView widget in the layout file. Create a new layout file that will represent the UI of each item in the recyclerview.

Furthermore, create a Recyclerview adapter class and a ViewHolder class which the recyclerview will use as its own adapter.

In other to get a visual understanding of what we are going to create in this android tutorial, I have add below some screen shots from the application.

SOME SCREENSHOT FROM THE APPLICATION

android butterknife

CREATE NEW ANDROID PROJECT

Lets start to soil our hands in code. Start up your IDE. For this tutorial, I am using the following tools and environment, feel free to use what works for you.

Windows 10

Android Studio

Sony Xperia ZL

Min SDK 14

Target SDK 25

To create a new android application project, follow the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidButterknifeExample

Package: com.inducesmile.androidbutterknifeexample

Select Empty Activity

Name your activity: MainActivity

Keep other default selections

Continue to click on next button until Finish button is active, then click on Finish Button.

Build.gradle for Dependencies and Android-apt plugin

We will move over to the build.gradle file. One thing we need to do is to add android-apt in the project level dependencies and in the Module level build.gradle, we will add the android-apt plugin below the android plugin.

Butter Knife uses the android-apt plugin because of the following reasons

1. Allow to configure a compile time only annotation processor as a dependency, not including the artifact in the final APK or library

2. Set up the source paths so that code that is generated from the annotation processor is correctly picked up by Android Studio.

Now, open your project level build.gradle and add the code below.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.1'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
allprojects {
    repositories {
        jcenter()
    }
}
task clean(type: Delete) {
    delete rootProject.buildDir
}

Also, open the module level build.gradle and add the code below.

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
    compileSdkVersion 25
    buildToolsVersion "24.0.1"
    defaultConfig {
        applicationId "com.inducesmile.androidbutterknifeexample"
        minSdkVersion 14
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.0.0'
    compile 'com.android.support:design:25.0.0'
    compile 'com.android.support:cardview-v7:25.0.0'
    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'
    testCompile 'junit:junit:4.12'
}

 STRINGS.XML

We are going to update our project strings.xml file located in the values folder inside the res folder. Open the file and add the code below to it.

<resources>
    <string name="app_name">Android ButterKnife Example</string>
    <string name="ferrari">Ferrari</string>
</resources>

COLORS.XML

Open the colors.xml file in the same location as the strings.xml file and add the code below to the file.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#63697a</color>
    <color name="colorPrimaryDark">#3c4357</color>
    <color name="colorAccent">#5E433C</color>
    <color name="colorWhite">#ffffff</color>
    <color name="colorHighlight">#DDD2CF</color>
</resources>

 Lets create layout file for our app UI

activity_main.xml

Open the activity_main.xml file that was created by us. If you do not select default activity creation, you can create a new activity class and name it MainActivity.java.

In the main layout file, we are going to add a RecyclerView widget. This layout is simple and easy to understands.

Open the activity_main.xml and add the code below.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.inducesmile.androidbutterknifeexample.MainActivity">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/car_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:scrollbars="none" />
</RelativeLayout>

 car_layout.xml

Create a new layout file in the layout folder inside the res folder. Name this layout file car_layout.xml or anything you wish. This will represent the UI of each list item of the recyclerview widget we create above.

Open this layout file and add the code below

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/direction_card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="1dp"
    card_view:cardElevation="4dp"
    card_view:cardUseCompatPadding="true">
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/car_type"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:adjustViewBounds="true"
            android:scaleType="centerCrop"
            android:src="@drawable/car1"
            android:contentDescription="@string/app_name"/>
        <TextView
            android:id="@+id/car_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/ferrari"
            android:textColor="@color/colorPrimaryDark"
            android:layout_gravity="bottom"
            android:gravity="center"
            android:padding="10dp"
            android:textStyle="bold"
            android:background="@color/colorHighlight"
            android:textSize="20sp"/>
    </FrameLayout>
</android.support.v7.widget.CardView>

 CarAdapter.java

Create a new java class file in your project package folder and name it CarAdapter. The adapter will bind our data source to each item list in the recyclerview instance.

This class will inflate a layout file that we have created above which represents an item view of the recyclerview.

The inflated layout view reference will be passed as a parameter to the instance of the CarViewHolder which is created below.

Open the CarAdapter class and add the code below to it.

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.List;
public class CarAdapter extends RecyclerView.Adapter<CarViewHolder>{
    private static final String TAG = CarAdapter.class.getSimpleName();
    private Context context;
    private List<CarObject> carList;
    public CarAdapter(Context context, List<CarObject> carList) {
        this.context = context;
        this.carList = carList;
    }
    @Override
    public CarViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(context).inflate(R.layout.car_layout, parent, false);
        return new CarViewHolder(view);
    }
    @Override
    public void onBindViewHolder(CarViewHolder holder, final int position) {
        CarObject carObject = carList.get(position);
        holder.carName.setText(carObject.getCarName());
        int imageId = getResourseId(context, carObject.getCarType(), "drawable", context.getPackageName());
        holder.carType.setImageResource(imageId);
        holder.carType.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Selected index " + position, Toast.LENGTH_LONG).show();
            }
        });
    }
    @Override
    public int getItemCount() {
        return carList.size();
    }
    public static int getResourseId(Context context, String pVariableName, String pResourcename, String pPackageName) throws RuntimeException {
        try {
            return context.getResources().getIdentifier(pVariableName, pResourcename, pPackageName);
        } catch (Exception e) {
            throw new RuntimeException("Error getting Resource ID.", e);
        }
    }
}

 CarViewHolder.java

Create another new Java class file and name it CarViewHolder. Since this class has a reference to the car_layout.xml file we create above, we will use the Butter knife view binding to bind the View widgets in the layout file.

Open the file and add the following code to it.

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
public class CarViewHolder extends RecyclerView.ViewHolder{

    @BindView(R.id.car_name) public TextView carName;
    @BindView(R.id.car_type) public ImageView carType;

    public CarViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }
}

Right now you can see the magic and how concise the code is.

MainActivity.java

Open the MainActivity class, we will also bind the recyclerview widget that was add to the activity_main.xml to this class as shown below

@BindView(R.id.car_list)RecyclerView recyclerView;

In the onCreate(Bundle savedInstanceState method of the Activity class, call bind method and pass the activity reference to it.

ButterKnife.bind(this);

The remaining code is to instantiate the adapter and pass it to the recyclerview. Add the code below to the file.

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();
    @BindView(R.id.car_list)RecyclerView recyclerView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        GridLayoutManager mGrid = new GridLayoutManager(MainActivity.this, 2);
        recyclerView.setLayoutManager(mGrid);
        recyclerView.setHasFixedSize(true);
        CarAdapter mAdapter = new CarAdapter(MainActivity.this, getTestData());
        recyclerView.setAdapter(mAdapter);
    }
    public List<CarObject> getTestData() {
        List<CarObject> cars = new ArrayList<CarObject>();
        cars.add(new CarObject("Ferrari", "car1"));
        cars.add(new CarObject("Bugatti", "car2"));
        cars.add(new CarObject("Ford Truck", "car3"));
        cars.add(new CarObject("Toyota", "car4"));
        cars.add(new CarObject("Honda", "car5"));
        cars.add(new CarObject("Mazda", "car6"));
        return cars;
    }
}

 CarObject

The last thing to do is to create an entity class. Create a new Java class file and name it CarObject.java. Open the file and add the code below to it.

public class CarObject {
    private String carName;
    private String carType;
    public CarObject(String carName, String carType) {
        this.carName = carName;
        this.carType = carType;
    }
    public String getCarName() {
        return carName;
    }
    public String getCarType() {
        return carType;
    }
}

If you have any question or suggestion about Butter Knife kindly leave a message in the comment section below.

This brings us to the end of this tutorial. I hope that you have learn something. Run your app and see for yourself.

You can download the code for this tutorial below. If you are having hard time downloading the tutorial, kindly contact me.

Remember to subscribe with your email address to be among the first to receive my new android blog post once it is published.

OTHER INTERESTING POSTS:

Add a Comment