浅析listview及Adapter原理一

ListView作为常用的列表控件,通常会定义不同适配器以承载其所绑定数据的特殊显示。常用的适配器(ArrayAdapter,
BaseAdapter等)也都用过,但是大家有没有考虑过为什么要用适配器?

问题一:适配器是承载数据的,如何跟listview建立联系?
    疑问我们需要了解适配器Adapter基础接口:registerDataSetObserver  (注册数据监听),unregisterDataSetObserver  (取消数据监听) 。这种设计意图很明显,数据发生变化的时候同步通知到观察者本身。而观察者是谁?我们调用adapter的时候并没有去注册任何监听,唯一跟listview交互的入口也就setAdapter()。

查阅setAdapter方法源码可知:
 
if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

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

的确,listview内部注册了适配器监听(这个时候适配器也就和listview建立关联)。

问题二: 适配器何时需要通知ListView去变化?

我们先看Adpater的实现类BaseAdapter,大家通常都会用到 notifyDataSetChanged(), notifyDataSetInvalidated(),然后ListView就发生了变化。


BaseAdapter部分源码:
    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();
    }




可以发现最终调用的是listview所注册的观察者中(onInvalidate, onChange)


问题三:适配器数据发生变化,listview本身发生了什么变化?

我们看最终dataobserver中做了什么 (AdapterDataSetObserver为adapterview的内部类):

  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();
        }

       @Override
        public void onInvalidated() {
            mDataChanged = true;

            if (AdapterView.this.getAdapter().hasStableIds()) {
                // Remember the current state for the case where our hosting activity is being
                // stopped and later restarted
                mInstanceState = AdapterView.this.onSaveInstanceState();
            }

            // Data is invalid so we should reset our state
            mOldItemCount = mItemCount;
            mItemCount = 0;
            mSelectedPosition = INVALID_POSITION;
            mSelectedRowId = INVALID_ROW_ID;
            mNextSelectedPosition = INVALID_POSITION;
            mNextSelectedRowId = INVALID_ROW_ID;
            mNeedSync = false;

            checkFocus();
            requestLayout();
        }


  最终知道了,listview本身调用requestlayout实现全局刷新。
     
























猜你喜欢

转载自blog.csdn.net/u011098381/article/details/79214861