ListView not refreshing already-visible items

后端 未结 3 1988
长情又很酷
长情又很酷 2020-12-03 05:23

I\'m displaying a list of contacts (name + picture) using the ListView. In order to make the initial load fast, I only load the names first, and defer picture l

3条回答
  •  清歌不尽
    2020-12-03 05:49

    Here I go answering my own question with a hackaround that I've settled on. Apparently, notifyDataSetChanged() is only to be used if you are adding / removing items. If you are updating information about items that are already displayed, you might end up with visible items not updating their visual appearance (getView() not being called on your adapter).

    Furthermore, calling invalidateViews() on the ListView doesn't seem to work as advertised. I still get the same glitchy behavior with getView() not being called to update on-screen items.

    At first I thought the issue was caused by the frequency at which I called notifyDataSetChanged() / invalidateViews() (very fast, due to updates coming from different sources). So I've tried throttling calls to these methods, but still to no avail.

    I'm still not 100% sure this is the platform's fault, but the fact that my hackaround works seems to suggest so. So, without further ado, my hackaround consists in extending the ListView to refresh visible items. Note that this only works if you're properly using the convertView in your adapter and never returning a new View when a convertView was passed. For obvious reasons:

    public class ProperListView extends ListView {
    
        private static final String TAG = ProperListView.class.getName();
    
        @SuppressWarnings("unused")
        public ProperListView(Context context) {
            super(context);
        }
    
        @SuppressWarnings("unused")
        public ProperListView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @SuppressWarnings("unused")
        public ProperListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        class AdapterDataSetObserver extends DataSetObserver {
            @Override
            public void onChanged() {
                super.onChanged();
    
                refreshVisibleViews();
            }
    
            @Override
            public void onInvalidated() {
                super.onInvalidated();
    
                refreshVisibleViews();
            }
        }
    
        private DataSetObserver mDataSetObserver = new AdapterDataSetObserver();
        private Adapter mAdapter;
    
        @Override
        public void setAdapter(ListAdapter adapter) {
            super.setAdapter(adapter);
    
            if (mAdapter != null) {
                mAdapter.unregisterDataSetObserver(mDataSetObserver);
            }
            mAdapter = adapter;
    
            mAdapter.registerDataSetObserver(mDataSetObserver);
        }
    
        void refreshVisibleViews() {
            if (mAdapter != null) {
                for (int i = getFirstVisiblePosition(); i <= getLastVisiblePosition(); i ++) {
                    final int dataPosition = i - getHeaderViewsCount();
                    final int childPosition = i - getFirstVisiblePosition();
                    if (dataPosition >= 0 && dataPosition < mAdapter.getCount()
                            && getChildAt(childPosition) != null) {
                        Log.v(TAG, "Refreshing view (data=" + dataPosition + ",child=" + childPosition + ")");
                        mAdapter.getView(dataPosition, getChildAt(childPosition), this);
                    }
                }
            }
        }
    
    }
    

提交回复
热议问题