ListView所用到的观察者模式浅析

版权声明:本文为博主原创文章,转载请注明原帖地址,谢谢 https://blog.csdn.net/AooMiao/article/details/67632856

前言:在我们使用listview的时候,例如使用网络请求返回一个数据显示在listview上,对listview里的子控件赋值后,我们都会调用adapter.notifyDataSetChanged()方法来刷新listview,界面就显示了那个数据,其中的原理是通过观察者模式来实现的。这里以BaseAdapter为例

BaseAdapter源码

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

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

    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }

    ............
}

说明:BaseAdapter 里面定义了一个具体被观察者mDataSetObservable ,还有四个方法(注重前三个):注册观察者,删除观察者,通知观察者干活

listview.setAdapter源码

public class ListView extends AbsListView {
    .................
    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
        ............
        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;//!!!
        }

        super.setAdapter(adapter);

        if (mAdapter != null) {
            ............
            mDataSetObserver = new AdapterDataSetObserver();//!!!
            mAdapter.registerDataSetObserver(mDataSetObserver);//!!!
            ............
        } 
    }
    .................
}

说明:刚开始会先判断是否已经有别的adapter和listview绑定了,有就注销之前的具体观察者(免得待会要通知它)
注意看我标注的//!!!那三行代码:

  • 把adapter参数赋给成员变量mAdapter;
  • 定义一个AdapterDataSetObserver对象
  • 调用mAdapter(实际上这里是BaseAdapter对象)注册方法注册AdapterDataSetObserver对象(干活那个)
    不难理解AdapterDataSetObserver肯定是继承了抽象观察者类的

    下面看AdapterDataSetObserver源码:

AdapterDataSetObserver 定义在抽象类AbsListView类中

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }

        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    }

调用onChanged方法里面会调用父类super.onChanged()方法,如下:

    class AdapterDataSetObserver extends DataSetObserver {

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

            if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                    && mOldItemCount == 0 && mItemCount > 0) {
                AdapterView.this.onRestoreInstanceState(mInstanceState);
                mInstanceState = null;
            } else {
                rememberSyncState();
            }
            checkFocus();
            requestLayout();
    }

说明:是不是很清楚了,它继承了抽象观察者类,重写onChanged()方法,里面逻辑就是把listview的界面重新布局,让数据重新显示。

总结

  • BaseAdapter里面有一个具体被观察者
  • listview.setAdapter(BaseAdapter对象)里面生成一个具体观察者,调用BaseAdapter对象注册具体观察者
  • 调用adapter.notifyDataSetChanged()方法后,adapter就是BaseAdapter对象,所以会调用BaseAdapter里面的具体被观察者mDataSetObservable的notifyChanged()方法(通知列表的所有观察者干活)
  • 调用AdapterDataSetObserver的onChanged()方法,显示数据

观察者模式让数据和界面都依赖于借口,实现了解耦,方便扩展工作。

猜你喜欢

转载自blog.csdn.net/AooMiao/article/details/67632856