Android Working with ButterKnife ViewBinding Library
ButterKnife is an Android library for view injection, that injects views into android activities or fragments using annotations.
One quick example; If we use @BindView annotation it helps avoid writing findViewById() method within our code. It’s because the @BindView annotation automatically typecasts the view element.
Butterknife does not simply provide view binding alone, it also provides a lot of other options like String binding, dimens binding, drawables binding, click events binding, and many more.
1. Basic Setup
First thing to do is to add ButterKnife library to your project by adding the below dependencies in your project level build.gradle file.
1 2 3 4 5 6 7 |
dependencies { // Butterknife dependencies compile 'com.jakewharton:butterknife:8.8.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1' } |
After adding these to the file, simply sync your project and continue with next step.
2. The working in a basic Activity class file
After adding the dependencies to the gradle, all the annotations will become available to import. We will see how @BindView and @OnClick annotations can be used.
For example, Let us consider we have the below layout having a TextView, an EditText and a Button.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <TextView android:id="@+id/text_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Email" /> <EditText android:id="@+id/input_title" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btn_submit" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dimens_18" android:text="@string/submit" /> </LinearLayout> |
To make the views available in the activity, we need to follow the below steps.
1. call @BindView along with the id of the view while declaring the view variable.
@BindView(R.id.text_title)
2. After calling setContentView() method, Call ButterKnife.bind(this).
1 2 3 4 5 6 7 8 |
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // bind the view using butterknife ButterKnife.bind(this); } |
Thus the class file will finally look like,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class MainActivity extends AppCompatActivity { @BindView(R.id.text_title) TextView textTitle; @BindView(R.id.input_title) EditText inputTitle; @BindView(R.id.btn_submit) Button btnSubmit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // binding the view using butterknife ButterKnife.bind(this); } @OnClick(R.id.btn_submit) public void onButtonClick(View view) { Toast.makeText(getApplicationContext(), "Email: " + inputName.getText().toString(), Toast.LENGTH_SHORT).show(); } } |
3. Within Fragments
Butterknife in fragments is the same as in an Activity, with an exception that the ButterKnife.bind() method usage is different. In a fragment, the inflated view will be passed as param along with the target parameter. Since the life cycle methods are little different in fragments, you should use the Unbinder to unbind the view within onDestroyView() method.
Carefully look down the below example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public class bindingFragment extends Fragment { Unbinder unbinder; @BindView(R.id.text_title) TextView textTitle; @BindView(R.id.btn_submit) Button btnSubmit; @BindView(R.id.input_title) EditText inputTitle; public bindingFragment() { // Empty public constructor // This is required } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // we don't use ButterKnife.bind() method here in Fragments } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_binding, container, false); // bind view using butter knife unbinder = ButterKnife.bind(this, view); return view; } @Override public void onDestroyView() { super.onDestroyView(); // unbind the view to free some memory unbinder.unbind(); } } |
4. Within Resources ( Strings, Colors, Dimens, Drawables etc,. )
Butterknife not just allows binding of views, but also bind other resources like strings, colors, dimens, and drawables.
Below example demonstrates the usages of multiple annotations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public class MainActivity extends AppCompatActivity { @BindView(R.id.text_title) TextView textTitle; @BindColor(R.color.colorPrimaryDark) int colorTitle; @BindView(R.id.icon) ImageView imageIcon; @BindDrawable(R.mipmap.launcher_icon) Drawable drawableIcon; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // binding the view using butterknife ButterKnife.bind(this); // setting label color textTitle.setTextColor(colorTitle); // displaying logo using drawable imageIcon.setImageDrawable(drawableIcon); } } |
Conclusion
Not only ButterKnife allows binding views, but also it provides a lot of other binding options such as binding Click Listener and list Adapters too. It reduces the boilerplate of common patterns and simplifies the code and makes it more human readable.