Kotlin Meteor: findViewById dead as Dinosaurs

findViewById(int) is an essential and ubiquitous method call that plods in your Activities, Views, Fragments and Adapters. It sometimes goes out of control but can be tamed with projects like Butter Knife, InjectView or Android Annotations. Being verbose and slow, the results should be cached when used frequently and hence the ViewHolder pattern.

Sometimes, the number of lines of code could be as little as a Compsognathus or could grow large and wild like a T-Rex. Check it out for yourself.

Regular Code

private EditText mEmailEditText;
private EditText mPasswordEditText;
private EditText mConfirmPasswordEditText;
private Spinner  mAgeSpinner;
private Spinner  mCountrySpinner;
private Spinner  mStateOrProvinceSpinner;
private CheckBox mIAgreeCheckBox;
private Button   mRegisterButton;

protected void onCreate(Bundle savedInstanceState) {
    super(savedInstanceState);
    setContentView(R.id.activity_register);

    mEmailEditText = (EditText) findViewById(R.id.emailEditText);
    mPasswordEditText = (EditText) findViewById(R.id.passwordEditText);
    mConfirmPasswordEditText = (EditText) findViewById(R.id.confirmPasswordEditText);
    mAgeSpinner = (Spinner) findViewById(R.id.ageSpinner);
    mCountrySpinner = (Spinner) findViewById(R.id.countrySpinner);
    mStateOrProvinceSpinner = (Spinner) findViewById(R.id.stateOrProvinceSpinner);
    mIAgreeCheckBox = (CheckBox) findViewById(R.id.iAgreeCheckBox);
    mRegisterButton = (Button) findViewById(R.id.registerButton);
}

All my hard work can be explained in a simple sentence – obtain references to my views. The problem is mitigated when using a view binding library, but you still need visible field declarations.

Butter Knife

@InjectView(R.id.emailEditText)
EditText mEmailEditText;

@InjectView(R.id.passwordEditText)
EditText mPasswordEditText;

@InjectView(R.id.confirmPasswordEditText)
EditText mConfirmPasswordEditText;

@InjectView(R.id.ageSpinner)
Spinner  mAgeSpinner;

@InjectView(R.id.countrySpinner)
Spinner  mCountrySpinner;

@InjectView(R.id.stateOrProvinceSpinner)
Spinner  mStateOrProvinceSpinner;

@InjectView(R.id.iAgreeCheckBox)
CheckBox mIAgreeCheckBox;

@InjectView(R.id.registerButton)
Button mRegisterButton;

protected void onCreate(Bundle savedInstanceState) {
    super(savedInstanceState);
    setContentView(R.id.activity_register);

    ButterKnife.inject(this);
}

Better, but still not subtle. This is the farthest Java can take you. Kotlin as a language itself could only take you so far.

Edit: Butter Knife doesn’t stop here. It has several other features like listener injections, view lists, resource binding, nullifying view references, etc., If you are still using Java for development, it is your best bet.

With the not so advertised Kotlin Android Extensions by JetBrains, your code will look like this,

Kotlin Android Extensions

import kotlinx.android.synthetic.activity_register.*

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_register)
}

Is that all? Yeah, that’s all of it 😉 and I am sober. CHECK. Notice the import statement.

import kotlinx.android.synthetic.<layout>.*

This statement imports all the widgets in the specified layout as properties. These view properties are named after their XML IDs and can be accessed directly. For instance, if you want to set a click listener for the register button. You can do,

registerButton.setOnClickListener(this) // R.id.registerButton

Next Steps

Check out the Getting Started guide to get started with Kotlin for Android Development and the Kotlin Android Extensions post to reap the above mentioned benefits. I like where this is going, what are your thoughts?

3 comments

  1. Mohammed Ersan · March 23, 2015

    But Annotations View Injection doesn’t work with “Library” project!!

    Like

  2. Pingback: Android :: ลด ละ เลิกการใช้ findViewById() !!!

Leave a comment