Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Integrating ButterKnife 8.4.0 for Android View Injection

Tech 2

ButterKnife streamlines Android UI development by generating boilerplate-free view lookups and event handlers at compile time. The framework eliminates explicit findViewById() calls and anonymous inner classes for listeners, resulting in cleaner activity and fragment structures. Because injection happens during compilation, there is negligible impact on application performance.

Gradle Setup

Version 8.4.0 relies on the android-apt plugin. Configure the project root build.gradle:

buildscript {
    repositories { jcenter() }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.2'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

allprojects {
    repositories { jcenter() }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

Apply the plugin and declare libraries in the module build.gradle:

apply plugin: 'com.android.application'
apply plugin: 'android-apt'

android {
    compileSdkVersion 24
    defaultConfig { 
        minSdkVersion 14
        targetSdkVersion 24 
    }
}

dependencies {
    compile 'com.jakewharton:butterknife:8.4.0'
    apt 'com.jakewharton:butterknife-compiler:8.4.0'
}

Field Binding

Attach the @BindView annotation to fields referencing UI components. The field scope must remain package-private, protected, or public; static and private modifiers trigger compilation errors. Initialize injections with in the lifecycle phase immediately following layout inflation.

package com.dev.sample.ui;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import butterknife.BindView;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.action_submit)
    Button submitAction;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        submitAction.setText("Process Request");
    }
}

Multiple View Collections

The @BindViews annotation maps a group of identifiers to a List<T>. This simplifies uniform styling or property updates across sibling elements.

package com.dev.sample.ui;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import java.util.List;
import butterknife.BindViews;
import butterknife.ButterKnife;

public class DashboardActivity extends AppCompatActivity {

    @BindViews({ R.id.header_label, R.id.sub_title, R.id.footer_status })
    List<TextView> statusLabels;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_dashboard);
        ButterKnife.bind(this);
        
        for (int i = 0; i < statusLabels.size(); i++) {
            statusLabels.get(i).setText("Status Node " + (i + 1));
        }
    }
}

Fragment Lifecycle Handling

Fragments require a two-argument bind call passing the inflated view hierarchy. Injection should ocurr after inflate() but before returning the view reference.

package com.dev.sample.fragments;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import butterknife.BindView;
import butterknife.ButterKnife;

public class MediaPanel extends Fragment {

    @BindView(R.id.media_display)
    ImageView mediaView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
        View baseView = inflater.inflate(R.layout.fragment_media, container, false);
        ButterKnife.bind(this, baseView);
        mediaView.setImageResource(R.drawable.placeholder_image);
        return baseView;
    }
}

Resource Field Injection

External resources can be bound directly to member variables using specialized annotations.

package com.dev.sample.config;

import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.EditText;
import android.widget.RatingBar;
import butterknife.*;

public class SettingsScreen extends AppCompatActivity {

    @BindView(R.id.input_field) EditText userField;
    @BindView(R.id.rating_control) RatingBar scoreBar;

    @BindString(R.string.greeting_msg) String welcomeText;
    @BindArray(R.array.region_options) String[] locationData;
    @BindBitmap(R.drawable.logo_icon) Bitmap companyLogo;
    @BindColor(R.color.primary_theme) int accentColor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);
        ButterKnife.bind(this);
        
        userField.setHint(welcomeText);
        scoreBar.setProgress(5);
        // companyLogo and accentColor are now valid references
    }
}

Event Delegation via Annotations

Replace listener implementations with direct method annotations. Return types and signatures are strictly enforced by the compiler.

package com.dev.sample.interactions;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnLongClick;

public class ActionHub extends AppCompatActivity {

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

    @OnClick(R.id.trigger_button)
    public void executePrimaryAction() {
        Toast.makeText(this, "Short tap registered", Toast.LENGTH_SHORT).show();
    }

    @OnLongClick(R.id.trigger_button)
    public boolean handleExtendedInteraction() {
        Toast.makeText(this, "Hold gesture detected", Toast.LENGTH_LONG).show();
        return true; // Consumes the event
    }
}

Automated Code Generation

The Zelezny plugin accelerates setup by scanning layout XML files. Position the text cursor on the setContentView(R.layout.your_layout) statemant within your Activity. Invoke the generation shortcut, select the target views from the modal dialog, and confirm. The plugin automatically produces the necessary @BindView declarations and ButterKnife.bind(this) invocation. For adapter architectures, enable the CreateViewHolder option during selection to inject @BindView directly into custom ViewHolder classes, optimizing recycler list performance.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.