findViewById slow inside ListView adapters

I was reading an article over on charlie.collins’s blog about using a ViewHolder class to cache the results of a findViewById() when used inside the getView() of a list’s adapter. I gave his recommendation a try and I did notice a speed improvement in my app so the observation that findViewById() is a performance hit has enough merit to go out of your way to enable some kind of caching mechanism.

While Charlie went the route of creating a class to hold the various views he was interested in, I decided to take a slightly different approach and make use of the alternative setTag(int, Object) function instead.

protected Object getViewHandle(View aParentView, int aViewToFind) {
    Object v = aParentView.getTag(aViewToFind);
    if (v==null) {
        v = aParentView.findViewById(aViewToFind);
        aParentView.setTag(aViewToFind,v);  
    }
    return v;
}

I would use this getViewHandle() function in the list’s adapter in following way:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View theItemView = convertView;
    if (theItemView==null) {
        theItemView = ((LayoutInflater)getContext().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.my_item_layout,null);
    }
    TextView tv = (TextView)getViewHandle(theItemView,R.id.some_text_view);
    ...
}

A downside to this technique is that it is only available in API 4+ (2.0+).

If you need to work with Android pre-2.0, a drop-in replacement to the getViewHandle() function would be similar to this one:

class ViewCacher {
    protected HashMap<Integer,View> mCache = new HashMap<Integer,View>();

    public View getViewHandle(View aParentView, Integer aViewToFind) {
        View v = mCache.get(aViewToFind);
        if (v==null) {
            v = aParentView.findViewById(aViewToFind);
            mCache.put(aViewToFind,v);  
        }
        return v;
    }
}

protected View getViewHandle(View aParentView, int aViewToFind) {
    ViewCacher vc = (ViewCacher)aParentView.getTag();
    if (vc==null) {
        vc = new ViewCacher();
        aParentView.setTag(vc);
    }
    return vc.getViewHandle(aParentView, aViewToFind);
}

 

On Thursday, June 16, 2011, xjaphx asked the question…
Hi, Code Monkey, I’ve just got a little wondering how you could measure the ViewHolder pattern performance in order to prove that it’s better than regular calling findViewById() for each getView() callbacks?

UCM responds: My proof is a bit too complex to place here, so I created a new blog post that explains it.

Leave a Reply

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