ListView adapter notifyDataSetChanged() track

134 篇文章 0 订阅
113 篇文章 0 订阅

ListView 为了方便使用,自己在setAdapter()的时候就会register 一个新的AdapterDataSetObserver,以响应之后的adapter的notifyDataSetChanged(),本质就是一个观察者模式的实现:

@Override
    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

..................................................
        super.setAdapter(adapter);

        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);
......................................................
}


BaseAdapter:

    下面的操作全部委托给mDataSetObservable了:
    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    而 private final DataSetObservable mDataSetObservable = new DataSetObservable();


DataSetObservable:

    public void notifyChanged() {
        synchronized(mObservers) {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }
挨个调用在自己这里注册的Observer的onChanged(),

那么对于ListView, 就一定会调用ListView自己register的AdapterDataSetObserver,

AdapterDataSetObserver定义在AbsListView中,是ListView的父类,

而 AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver:

class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();

            // Detect the case where a cursor that was previously invalidated has
            // been repopulated with new data.
            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            requestLayout();
        }
................................................................
}
可以看到,notifyDataSetChanged()最重要的是调用到了AdaperView(其实这里是ListView)的requestLayout,

这样就在这一次出发的layout()(onLayout())里,就可以更新要显示的数据和View了。

ListView是自己直接为自己register了一个DataSetObserver, 但是AdapterView自己是不会配的,用的话,要自己register一个,

这也符合子类(ListView)扩展父类(AdapterView)的方式.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 开发中,ListView 是一个常用的控件,用于展示列表数据。当数据源发生改变时,我们可以通过调用 adapternotifyDataSetChanged 方法来通知 ListView 刷新数据。不过有时候,调用该方法后 ListView 并没有刷新成功,这是为什么呢? 通常情况下,adapter 调用 notifyDataSetChanged 方法后 ListView 会自动刷新,但有一些情况下会出现刷新失败的情况,主要原因如下: 1. 数据源未更新 notifyDataSetChanged 方法只能刷新 adapter 中的数据源,如果数据源没有更新,那么 ListView 就无法刷新。因此,在调用该方法之前,必须要确保 adapter 中的数据源已经更新。 2. ListView 高度计算错误 当 ListView 的高度计算错误时,可能会导致刷新失败。当 ListView 的高度设置为 wrap_content 时,它的高度会根据内容自适应,这时如果数据源发生变化,ListView 的高度也会发生变化,但是 ListView 并不会自动刷新,需要手动调用 requestLayout 方法来重新计算布局。 3. ListView 处于滚动状态 当 ListView 处于滚动状态时,调用 notifyDataSetChanged 方法可能会失效。因为在滚动过程中,ListView 的布局已经被固定,此时调用 notifyDataSetChanged 方法并不会改变布局,只有当滚动停止后才会刷新数据。如果需要在滚动状态下刷新数据,可以尝试使用 notifyDataSetInvalidated 方法。 综上所述,ListView adapter 调用 notifyDataSetChanged 方法无效的原因可能是数据源未更新、ListView 高度计算错误或者 ListView 处于滚动状态。需要根据具体情况进行分析和解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值