ViewHolder pattern fixed my slow lists
Thursday, March 14, 2013So I shipped my first app with a list. Tested on my Nexus 4, looked good. Then someone opened it on a Galaxy Y and the scrolling was terrible. Like really bad.
Turns out findViewById() was the problem.
The bad code
This is what I was doing:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context)
.inflate(R.layout.item_row, parent, false);
}
TextView title = (TextView) convertView.findViewById(R.id.title);
TextView subtitle = (TextView) convertView.findViewById(R.id.subtitle);
Item item = items.get(position);
title.setText(item.getTitle());
subtitle.setText(item.getSubtitle());
return convertView;
}
The convertView check was already good. But findViewById() traverse the whole view tree every time. And getView() gets called alot when you scroll fast.
The fix
Cache the views. Thats it.
static class ViewHolder {
TextView title;
TextView subtitle;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context)
.inflate(R.layout.item_row, parent, false);
holder = new ViewHolder();
holder.title = (TextView) convertView.findViewById(R.id.title);
holder.subtitle = (TextView) convertView.findViewById(R.id.subtitle);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Item item = items.get(position);
holder.title.setText(item.getTitle());
holder.subtitle.setText(item.getSubtitle());
return convertView;
}
Now findViewById() only runs when inflating. After that the cached holder is reused.
Galaxy Y went from terrible to 60fps. PM was impressed, I didnt explain.
Why it works
setTag() attach any object to a View. When ListView recycle a row, you get back the same convertView with your tag still there.
Google saw everyone doing this and made it mandatory in RecyclerView. The ViewHolder is not optional anymore there.
In 2013 you had to know about it. Now its just how things work.
Lesson
Test on cheap phones. Your dev device lies to you.