Tip Android #36: Simplificar código con Butter Knife

04/07/2015
android tip

Butter Knife es una librería Open Source para Android que permite asociar los widgets y eventos a sus correspondientes atributos y métodos en el código Java mediante el uso de anotaciones. El objetivo es ahorrar la escritura de código eliminando las llamadas a findById, setOnClickListener, etc, haciendo de paso el código más simple y legible. Estas anotaciones pueden ser utilizadas en Activities, Fragments y Adapters.

Tomemos como ejemplo el siguiente layout con un EditText, un TextView y un Button

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    android:id="@+id/layout">

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:hint="@string/editText"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/textView"
        android:layout_below="@+id/editText"
        android:layout_marginTop="15dp"
        android:layout_alignRight="@+id/editText"
        android:layout_alignEnd="@+id/editText"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button"
        android:id="@+id/button"
        android:layout_marginTop="15dp"
        android:layout_below="@+id/textView"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />


</RelativeLayout>

Seguimos los siguientes pasos para utilizar Butter Knife

  1. Añadir la librería al proyecto.
    • Gradle/Android Studio: añadir la dependencia en el fichero build.gradle.
      dependencies {
          compile fileTree(dir: 'libs', include: ['*.jar'])
          compile 'com.jakewharton:butterknife:7.0.0'
      }
    • Maven. Incluir la dependencia en el pom.xml
      <dependency>
        <groupId>com.jakewharton</groupId>
        <artifactId>butterknife</artifactId>
        <version>7.0.0</version>
      </dependency>
      
    • Manualmente: descargar el .jar y ubicarlo en el directorio libs.
    • Para evitar problemas con la ofuscación de código es necesario añadir las siguientes líneas al fichero de configuración de proguard.

      -keep class butterknife.** { *; }
      -dontwarn butterknife.internal.**
      -keep class **$$ViewBinder { *; }
      
      -keepclasseswithmembernames class * {
          @butterknife.* ;
      }
      
      -keepclasseswithmembernames class * {
          @butterknife.* ;
      }
  2. Los atributos en los que se guardará la referencia a los widgets de la interfaz se anotarán con @Bind, indicando el id del layout.
    public class MainActivity extends Activity {
    
        @Bind(R.id.editText)
        EditText editText;
    
        @Bind(R.id.textView)
        TextView textView;
    ...
    
  3. Para los métodos que actúen como listeners la anotación dependerá del evento, en la versión 7.0.0 de Butter Knife disponemos de los siguientes: @OnCheckedChanged, @OnClick, @OnEditorAction, @OnFocusChange, @OnItemClick, @OnItemLongClick, @OnItemSelected, @OnLongClick, @OnPageChange, @OnTextChanged, @OnTouch.
     @OnClick(R.id.button)
        public void copy(Button button) {
            textView.setText(editText.getText());
        }
    
  4. Iniciar Butter Knife en cuanto se establezca el layout de la Activity.
     @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //IMPORTANTE!!!
            ButterKnife.bind(this);
            ...
    

ListView

Además de Activities, Butter Knife se puede utilizar en Fragments y Adapters. Por ejemplo, consideremos una ListView cuyas filas tienen el siguiente layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/title" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:id="@+id/subtitle" />
</LinearLayout>

En la Activity, tal y como hemos visto, vamos a “inyectar” el ListView y a definir un listener que muestre un Toast cada vez que se pulse en una de sus filas.

 @Bind(R.id.listView)
    ListView listView;

    private List<String> objects;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //IMPORTANTE!!!
        ButterKnife.bind(this);
        objects = new ArrayList<String>(20);
        for (int i = 0; i < 20; i++) {
            objects.add("object " + i);
        }
        listView.setAdapter(new CustomAdapter(this, objects));
    }   

    @OnItemClick(R.id.listView)
    public void onItemClick(int position) {
        Toast.makeText(this, objects.get(position), Toast.LENGTH_SHORT).show();
    }

La implementación de un ArrayAdapter siguiendo el ViewHolder pattern.

public class CustomAdapter extends ArrayAdapter<String> {

    private LayoutInflater layoutInflater;

    public CustomAdapter(Context context, List<String> objects) {
        super(context, 0, objects);
        layoutInflater = LayoutInflater.from(context);
    }

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        ViewHolder holder;
        if (view != null) {
            holder = (ViewHolder) view.getTag();
        } else {
            view = layoutInflater.inflate(R.layout.listview_row, parent, false);
            holder = new ViewHolder(view);
            view.setTag(holder);
        }

        holder.title.setText(getItem(position));
        holder.subtitle.setText(getItem(position));

        return view;
    }

    static class ViewHolder {
        @Bind(R.id.title)
        TextView title;
        @Bind(R.id.subtitle)
        TextView subtitle;

        public ViewHolder(View view) {
            ButterKnife.bind(this, view);
        }
    }

El proyecto completo para Android Studio se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.

<< TIPS ANDROID

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: