Simpler View Binding with Android

I recently wrote a couple of Android apps in the native Java language. One of the things I hated about this was the amount of boilerplate. First, I would create a UI element and give it an ID – something like:

    <TextView
        android:id="@+id/city_field"
        android:text="@string/default_city_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:textColor="#FFFFFF"
        android:textAppearance="?android:attr/textAppearanceLarge" />

Then I would go to my activity and add a private variable for each view element:

public class MainActivity extends AppCompatActivity implements LocationListener {
    ImageView c_refresh;
    TextView c_city, c_details, c_temperature, c_updated, weatherIcon;

Then, within the onCreate() method, I bind the view to the ID:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Get the ID of each field that we want to modify
        c_city = (TextView)findViewById(R.id.city_field);
        c_details = (TextView)findViewById(R.id.details_field);
        c_temperature = (TextView)findViewById(R.id.current_temperature_field);
        c_updated = (TextView)findViewById(R.id.updated_field);
        c_refresh = (ImageView)findViewById(R.id.refresh_button);
        weatherIcon = (TextView)findViewById(R.id.weather_icon);

That’s a lot of necessary boilerplate code and it obscures the real work that onCreate() is doing. Fortunately, someone else thought of this as well. A guy by the name of Jake Wharton, in fact. This was obviously such a big deal for him that he wrote a library for it called ButterKnife.

So, how does this library change things? Well, let’s take my example above. I have a city field in the UI – I’m not going to get rid of that. Then I have a private variable within the class. Finally, I want to do all the bindings at once. This is what my MainActivity class would look like with the new semantics:

import butterknife.BindView;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity implements LocationListener {
    /**
     * Bind the c_city variable to the UI
     */
    @BindView(R.id.city_field) TextView c_city;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        // The rest of your onCreate()
    }
}

You can also create a new super-class based on the AppCompatActivity that does the binding for you, so you never have to think about it. Just inherit from the new super-class and move on.

Sometimes, the small things are major improvements. In this case, I write less code, so there is less to go wrong and my code is much more readable – both wins in my book.

One thought

  1. Pingback: Dew Drop - June 19, 2017 (#2503) - Morning Dew

Comments are closed.