Efficient ListView’s in Android: View Holder Pattern


When we’re going to implement a good adapter, we have to take into account two things: reuse the convertView parameter and
variable of the getView() method to avoid inflating new View objects when it’s not needed.

To solve this you must use the ViewHolder pattern, which is what we’re going to explain in this little article

Not taking into account those advices may cause, sooner or later, the following findViewById() calls to provoke performance problems. This could be solved with the View Holder pattern.

To apply this pattern, we could simply create a nested class into the adapter that we’re using for the ListViews’ rows.

For example, if each of these rows contains 3 TextView (as we saw in the example: RESTFul app), we should include the class into ContactsArrayAdapter class

static class ContactsViewHolder {
	TextView txName;
	TextView txEmails;
	TextView txPhones
}

For the getView() method we have to make modifications. We’ve decided to separate the ContactsArrayAdapter class in a new file:


package es.jmanzano.json;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

/**
 * Adapter class to show the contacts
 */
public class ContactsArrayAdapter extends ArrayAdapter {

	/** Contacts list */
	private List contacts;

	/** Context */
	private Context context;

	public ContactsArrayAdapter(Context context, int textViewResourceId,
			List contacts) {
		super(context, textViewResourceId, contacts);
		this.context = context;
		this.contacts = contacts;
	}

	@Override
	public View getView(int position, View v, ViewGroup parent) {
		// Keeps reference to avoid future findViewById()
		ContactsViewHolder viewHolder;

		if (v == null) {
			LayoutInflater li = (LayoutInflater) getContext().getSystemService(
					Context.LAYOUT_INFLATER_SERVICE);
			v = li.inflate(R.layout.contact_row, parent, false);

			viewHolder = new ContactsViewHolder();
			viewHolder.txName = (TextView) v.findViewById(R.id.tvName);
			viewHolder.txEmails = (TextView) v.findViewById(R.id.tvEmails);
			viewHolder.txPhones = (TextView) v.findViewById(R.id.tvNumbers);

			v.setTag(viewHolder);
		} else {
			viewHolder = (ContactsViewHolder) v.getTag();
		}

		Contact contact = contacts.get(position);
		if (contact != null) {
			viewHolder.txName.setText(contact.getName());
			viewHolder.txEmails.setText(contact.getEmails().toString());
			viewHolder.txPhones.setText(contact.getNumbers().toString());
		}
		return v;
	}

	static class ContactsViewHolder {
		TextView txName;
		TextView txEmails;
		TextView txPhones;
	}
}

Here we can see how to use the setTag() method to set and get the ContactsViewHolder. This will manage all the visual data in our ListView and, as we can see, we can avoid the performance problem findViewById() due to we’re reusing the views thanks to ContactsViewHolder.



6 thoughts on Efficient ListView’s in Android: View Holder Pattern

  1. Pingback: TextView Wrap Performance Problem - Android-Hilfe.de

  2. Pingback: How to stop list recycling On Scroll of list View, in a custom cursor adapter android : Android Community - For Application Development

  3. Pingback: Large set of data in listview crashing the android app : Android Community - For Application Development

  4. Pingback: Changing elements at the top of an Adapter without repositioning lower items : Android Community - For Application Development

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>