Tidy and Optimize Your Java Code with Android Butter Knife
This article was updated in July 2016 to reflect updates to Android Butter Knife.
Creating code can sometimes be frustrating. Developers have to deal with redundant coding that is visually unattractive. In this article, I will introduce an injection library for Android development that can help create more beautiful code and recent updates introduced with version 8. Android Butter Knife is an open source view “injection” library for Android created by Jake Wharton.
Butter Knife is small, simple and lightweight, and it makes life as a developer easier. It allows developers to perform injection on arbitrary objects
, views
and OnClickListeners
so they can focus on writing useful code. Consider Android Butter Knife a reduction library. It replaces findViewById
with @Bind()
and set^^^^Listener
calls with @onClick()
making code cleaner and more understandable. Butter Knife enables focus on logic instead of glue code and reduces development time by reducing redundant coding.
Configure Your Project for Android Butter Knife
Before getting started with Butter Knife, you need to configure your Android project.
Open build.gradle at project level and add the following dependency
dependencies {
...
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
Open build.gradle(Module:app) (module level) and add the following dependencies.
dependencies {
...
compile 'com.jakewharton:butterknife:8.1.0'
apt 'com.jakewharton:butterknife-compiler:8.1.0'
}
And apply the plugin:
apply plugin: 'android-apt'
android {
...
}
Finally sync Gradle.
Butter Knife in action
Now that you have configured Butter Knife its time to move on to the main features this injection library can provide:
- Binding views and resources
- Event Listeners
- List adapters,
RecyclerView
implementation
Why use Butter Knife
The goal of this library is to help developers write better code, and it does so by trying to reduce the code used in the onCreate
method on an Activity
class and in onCreateView
on Fragment
s. All you need to write in these methods is the following:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
ButterKnife.bind(this);
//...
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_blank, container, false);
ButterKnife.bind(this, view);
return view;
}
In both the cases Butter Knife binds to the specified Android Activity
or View
targets to correctly act on the injections specified in these classes. All the view finding lines of code and the action listeners are implemented elsewhere, leaving these methods as clean as possible.
Binding views and resources
Butter Knife replaces the standard findViewById
call with @BindView
, followed by a view ID and it automatically casts the corresponding view in the corresponding layout. This representation of the code makes it more compact and readable.
Here’s an example of this “injection”:
@BindView(R.id.imageView) ImageView image;
@BindView(R.id.button) Button button;
You can do the same with app resources like String
, Drawable
and dimensions (dimen
, value
, etc). Here are all the possible bindings with Butter Knife.
@BindString(R.string.title) String title;
@BindDrawable(R.drawable.sitepoint) Drawable sitepointDrawable;
@BindColor(R.color.colorPrimary) int primaryColor;
Event Listeners
Butter Knife also makes setting event listeners of Android layout Views
easy and removes the listeners implementation from the key onCreate
and onCreateView
methods.
Here’s an example:
@OnClick(R.id.button)
public void ButtonClick() {
//Perform some action
}
This isn’t restricted to click
events, here are all the other events you can set.
Material Design
For the rest of this tutorial, I will focus on injecting Butter Knife features in Material Design views and components.
Open Android Studio and create an application with a Basic Activity.
What better component to test with than the FloatingActionButton
.
public class MainActivity extends AppCompatActivity {
//FloatingActionButton
@BindView(R.id.fab)
FloatingActionButton FAB;
@OnClick(R.id.fab)
public void SnackbarNotification(View view) {
Snackbar.make(view, "Great, it works with Material Design", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
//...
}
And as you can see in the image below it works as you would expect.
Adapters
Butter Knife works well with list adapters, but can it also work with other Material Design similar components such as the RecyclerView
adapter?
The process of building a RecyclerView
is long and complex, so I recommend you first read my article explaining how.
I will focus on the parts of the RecyclerView
related to Butter Knife, the ViewHolder
and view binding. The full code of this example is available on GitHub.
The ViewHolder
example of a RecyclerView
looks like this (In Recycler_View_Adapter.java).
public class View_Holder extends RecyclerView.ViewHolder {
@BindView(R.id.cardView)
CardView cv;
@BindView(R.id.textView)
TextView title;
@BindView(R.id.imageView)
ImageView imageView;
View_Holder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
This ViewHolder
class represents one row of the RecyclerView
with the following layout (row_layout.xml).
<android .support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/activity_vertical_margin"
app:cardCornerRadius="8dp"
app:cardElevation="8dp">
<imageview android:id="@+id/imageView"
android:layout_width="120dp"
android:layout_height="110dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="@color/abc_input_method_navigation_guard"
android:src="@drawable/butterknife"></imageview>
<textview android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|right"
android:layout_marginRight="40dp"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge"></textview>
</android>
In an Activity
class bind the RecyclerView
and provide data to its Adapter
(In MainActivity.java).
@BindView(R.id.recyclerview)
RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
ButterKnife.bind(this);
//Setup the RecyclerView
List<data> data = new ArrayList<>();
for (int i = 0; i < 15; i++) {
//Generate 15 data elements
data.add(new Data("Butter Knife", R.drawable.butterknife));
}
Recycler_View_Adapter adapter = new Recycler_View_Adapter(data, getApplication());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
Conclusion
Android Butter Knife helps you create cleaner and tidier code, handling a lot of the ugly boilerplate code that Android has become infamous for. Have you tried in your projects? I’d love to know if you found it useful or not.