Butterknife. Sorprendentemente sencillo, absolutamente imprescindible

Butterknife. Sorprendentemente sencillo, absolutamente imprescindible

Introducción

Si has desarrollado o desarrollas Android te habrás encontrado con que para inyectar las vistas en la lógica de la Activity necesitas hacer un uso intensivo del "findViewById". Para que no quede un churro doloroso de leer en el onCreate() solemos crear un método "initializeUI()" y aquí metemos el churro antes comentado con todos los findViewsByIds, este método nos podría quedar tal que así: private void initializeUI(){ textView1 = (TextView) findViewById(R.id.text_view_1); textView2 = (TextView) findViewById(R.id.text_view_2); textView3 = (TextView) findViewById(R.id.text_view_3); textView4 = (TextView) findViewById(R.id.text_view_4); textView5 = (TextView) findViewById(R.id.text_view_5); editText1 = (EditText) findViewById(R.id.edit_text_1); editText2 = (EditText) findViewById(R.id.edit_text_2); editText3 = (EditText) findViewById(R.id.edit_text_3); myList = (RecyclerView) findViewById(R.id.my_list); }Demasiado tedioso, ¿verdad?. Ahora veamos como quedaría este método con ButterKnife: private void initializeUI(){ }¿Ridículo verdad? Si. ¿Tiene trampa?, ¿Es magia?... No. Es Butterknife, una librería que, como habréis podido adivinar, nos servirá para inyectar las vistas (y recursos) de una forma mucho más elegante y limpia que la convencional.

Añadirlo al proyecto Android

Este es un paso realmente sencillo, simplemente deberemos añadir la dependencia a nuestro build.gradle (a nivel del módulo) dependencies { ... compile 'com.jakewharton:butterknife:7.0.1' }

Show me the code!

Butterknife se puede incluir en Activities, fragments, adapters... veamos como debemos usarlo en cada uno de ellos:

Activity

En este caso es muy sencillo, simplemente tendremos que declarar nuestras vistas como atributos como haríamos siempre, pero deberemos incluir la anotación @Bind(R.id.id_del_recurso). Adicionalmente, en el método onCreate() incluiremos la sentencia Butterknife.bind(this);. Esta sentencia hará el binding con el layout e inyectará todas las vistas. El código de una activity como la anterior quedaría tal que así (fijaos en que los atributos NO pueden ser privados): public class MainActivity extendes AppCompatActivity{ @Bind(R.id.tex_view_1) TextView textView1; @Bind(R.id.tex_view_2) TextView textView2; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Butterknife.bind(this);  //No olvidar!! } }¿Mucho más limpio que lo anterior verdad?

Fragment

En el caso del fragment el uso es muy parecido, cambiando sólo el método donde llamaremos al "Butterknife.bind()", que lo haremos en el onCreateView(): public class MyFragment extends Fragment { @Bind(R.id.tex_view_1) TextView textView1; @Bind(R.id.tex_view_2) TextView textView2; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_fragment, container, false); ButterKnife.bind(this, view); return view; } } Como podemos observar, el método utilizado ahora es el bind(this, view). Básicamente hacemos el binding entre la vista inflada y la instancia del fragment.

Adapters

En el caso de los adapters su uso es exactamente igual al del fragment. Si utilizamos una RecyclerView debemos hacer el binding en el ViewHolder, nos quedará algo como esto: public class RadioViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.name) TextView name; @Bind(R.id.logo) ImageView logo; @Bind(R.id.url) TextView url; View itemView; public RadioViewHolder(View itemView) { super(itemView); this.itemView = itemView; ButterKnife.bind(this, itemView); } }

Listas de vistas

Con Butterknife no solo podemos hacer un binding "normal" de atributos, sino que también los podemos agrupar en listas de una forma muy sencilla: public class MainActivity extendes AppCompatActivity{ @Bind({R.id.tex_view_1, R.id.tex_view_2}) List textViews; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Butterknife.bind(this); } }

Recursos

También podemos hacer binding de recursos como Strings, Drawables...public class MainActivity extendes AppCompatActivity{ @BindString(R.string.title) String title; @BindDrawable(R.drawable.my_drawable) Drawable myDrawable; @BindColor(R.color.red) int red; ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Butterknife.bind(this); } }Pero esto no es todo, puedes explorar la librería a fondo en (http://jakewharton.github.io/butterknife/)

Bonus track, limpiando un poco

Como veis hemos mejorado y limpiado mucho nuestro código pero... no hemos venido aquí a poner en cada Activity un ButterKnife.bind() no? que rollo... Para esto podemos hacer lo siguiente.

1. Crear una "BaseActivity" abstracta

public abstract class BaseActivity extendes AppCompatActivity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutId()); Butterknife.bind(this);  //No olvidar!! } public abstract int getLayoutId(); }

2. Nuestra activity extiende de BaseActivity

public class MainActivity extendes BaseActivity{ @Bind(R.id.tex_view_1) TextView textView1; @Bind(R.id.tex_view_2) TextView textView2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } public int getLayoutId(){ return R.layout.activity_main; } }Si hacemos que todas nuestras activities hereden de BaseActivity no tendremos que hacer el bind y encima empezamos a limpiar un poquito el proyecto, pero esto ya da para otra entrada :) PD: Este es mi primer artículo en Geeky Theory (espero que el primero de muchos), así que estoy abierto a todo tipo de sugerencias y críticas constructivas! :)