ListView View Holder Pattern

En esta entrada vamos a optimizar el uso de un adpatador creando una clase View Holder Pattern que evitará la llamada continua a findViewById() dentro del método getView() del Adapter.

Sin y Con el View Holder Pattern

Sin

Si nos fijamos en nuestro proyecto ListView Custom, veremos que el método getView() adapter recibe una vista, la convertView.

La primera vez que se carga, la convertView es null por lo que tenemos que inflar nuestro layout y encontrar el textView con findViewById().

La segunda vez que se carga, convertView ya no es null. No tenemos que inflar la vista otra vez, pero tenemos que volver a usar findViewById() y así el resto de veces que se llame, una para cada elmento de la lista. Funciona pero reduce el rendimiento, sobre todo si tenemos muchos elementos en la lista.

Con

La primera vez que se carga, la convertView es nula y tenemos que inflar nuestro list item layout, como antes, pero instanciamos (creamos) un objeto ViewHolder, buscamos el textView con findViewById() como antes, pero ahora lo asignamos a ese ViewHolder que hemos creado, y finalmente se lo asignamos como TAG al convertView.

La seguna vez que se carga, la convertView ya no ees nual y no tenemos que inflar el layout. Pero además ya no tenemos que llamar al findViewById() para el textView porque podemos acceder a el a través su objeto VieHolder.

Las siguientes veces tampoco.


Veamos cómo funciona paso a paso.

Creamos un Custom Adapter y lo vinculamos al  ListView

Para ello procederemos con en la entrada LIstView Custom

Creamos el ViewHolder

Básicamente se trata de crear un objeto con el TextView instanciado o buscado (el TextView o cualquier objeto del layout que queramos mantener).

Creamos la clase ViewHolder dentro del adaptador, pues no servirá desde fuera. Instanciamos un ViewHolder cuando el convertView viene a nulo, es decir la primera vez, con lo que en ese momento hacemos el findViewById e instanciamos el TextView desde R. Además, para que podamos rescatar el holder cuando el convertView no venga vacío, añadimos el holder recien creado como un Tag al convertView.

Si el convertViewn no viene a nulo rescatamos el holder y dispondremos de los objetos que guardamos en el.

El código sería:

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {

        ViewHolder holder;  //Creamos nuestro objeto ViewHolder

        if (convertView==null){
            //Inflamos el layout de nuestros items en nuestra vista v
            LayoutInflater inflater = LayoutInflater.from(this.context);
            convertView = inflater.inflate(R.layout.item_layout,null);

            holder = new ViewHolder();  // Lo asingamos la primera vez

            //instanciamos el ImageView o el TextView de nuestro Layout para los items.
            holder.tvNombre = convertView.findViewById(R.id.tvNombre);
            convertView.setTag(holder);  // establecemos como tag del convertView el objeto holder
        }
        else{
            holder=(ViewHolder) convertView.getTag();   //obtenemos el tag.
        }

        //Obtenemos el nombre de la lista según la posición que nos pasan.
        String selectedName = items.get(position);

        //En el textView si ponemos el nombre.
        holder.tvNombre.setText(selectedName);

        //Devolvemos la vista (nuestro layout) actualizada para la posición requerida.
        return convertView;
    }

    private class ViewHolder{
        private TextView tvNombre;
    }