[Android] Way to avoid using 'notifyDataSetChanged' when only one or two items are changed at Adapter.

Domain/Android 2012.10.23 09:07

When using Adapter (especially list), sometimes(actually very frequently) data of only one item(row) is changed.

In this case, usually, changing one-under-lying data is easy.

But, updating only one list item is different story.

To update that item to the screen, - changing look-and-feel regarding changed item -  easiest way is calling notifyDataSetChanged().

But, this re-bind views of all list items. This is wasteful.

To avoid this, we should get View of item associated, and then modify it directly.

At first glance, it is easy and "Item position to View" map seems to be useful. But, it's NOT.

Why?

AdapterView usually reuse Views. So, several positions become to share same view at "position to View" map.
That is, whenever try to update item at specific item, we need to check that that item has valid visible View or not.

But, this is not-easy at current(API 15) Android API.


My suggestion is using "View to position" map(henceforth VPMap).

At AdapterView, View is reused. So, Adapter doesn't have lot's of different Views.

So, key size of the VPMap is not large (usually at most 20~30).

And we can easily update recent valid visible position of View easily at getView() of Adapter.

See below sample code.

private final HashMap<View, Integer> mView2PosMap = new HashMap<View, Integer>();
...
public void
setItemActive(int pos) {
    if (pos == mActivePos)
        return;
    View v = Utils.findKey(mView2PosMap, mActivePos);
    if (null != v)
        setToInactive(v);
    v = Utils.findKey(mView2PosMap, pos);
    if (null != v)
        setToActive(v);

    mActivePos = pos;
}
...
@Override
public View
getView(int position, View convertView, ViewGroup parent) {
    View v;
    if (null != convertView)
        v = convertView;
    else
        v = UiUtils.inflateLayout(mContext, R.layout.row);

    mView2PosMap.put(v, position);
    ...
}
...
public static <k,v> K
findKey(HashMap<View, Integer> map, V value) {
    Iterator<k> iter = map.keySet().iterator();
    while(iter.hasNext()) {
        K key = iter.next();
        if (map.get(key).equals(value))
            return key;
    }
    return null;
}

Like above, with this VPMap we can easily find associated visible View and can update only one-updated-item-View without calling 'notifyDataSetChanged()'.


Trackback 0 : Comment 0