ArrayAdapter的notifyDataSetChanged方法与观察者模式的应用

ArrayAdapternotifyDataSetChanged方法是源码如下的:

    public void notifyDataSetChanged() {

        super.notifyDataSetChanged();

        mNotifyOnChange = true;

    }


调用父类的notifyDataSetChanged方法,并且将一个属性设置为true

mNotifyOnChange属性的说明是这样的:用来标识当数据源发生变化时,notifyDataSetChanged 方法是否必须被调用。该属性被广泛的用于ArrayAdapter对数据源进行修改的相应方法中,包括addaddAllinsertremoveclearsort方法。看一下其中add方法的源码:

public void add(T object) {

        synchronized (mLock) {

            if (mOriginalValues != null) {

                mOriginalValues.add(object);

            } else {

                mObjects.add(object);

            }

        }

       <span style="color:#FF0000;"> if (mNotifyOnChange)notifyDataSetChanged();</span>

}


当向数据源中添加了数据的时候,如果mNotifyOnChangetrue,就调用ArrayAdapternotifyDataSetChanged方法。

再回过头看ArrayAdapternotifyDataSetChanged方法,它执行了父类的notifyDataSetChanged方法,也就是BaseAdapternotifyDataSetChanged方法,看一下它的源码:

public void notifyDataSetChanged() {

        mDataSetObservable.notifyChanged();

}


该方法的说明是:通知所有“注册”的观察者们,内部数据已经发生了变化,所有用来显示这些数据的视图都应该刷新一下自己显示新的数据。

显然这里用到了观察者模式,而mDataSetObservable从名字就可以看出来,它是观察者模式中的“主题”(Subject),也就是被观察者。BaseAdapternotifyDataSetChanged实际就是调用了mDataSetObservablenotifyChanged方法。mDataSetObservableBaseAdapter的一个属性:

private final DataSetObservable mDataSetObservable = new DataSetObservable();


该属性的类型为DataSetObservable,跟进去看一下这个类以及它的notifyChanged方法:

public class DataSetObservable extends Observable<DataSetObserver> {

    public void <span style="color:#FF0000;">notifyChanged()</span> {

        synchronized(mObservers) {

            for (int i = mObservers.size() - 1;i >= 0; i--) {

                mObservers.get(i).onChanged();

            }

        }

    }

    public void notifyInvalidated() {

        synchronized (mObservers) {

            for (int i = mObservers.size() - 1;i >= 0; i--) {

               mObservers.get(i).onInvalidated();

            }

        }

    }

}


该类继承自Observable<T>,而Observable<T>JDK中专门为观察者模式中的“主题”(Subject)也就是被观察者设计的一个类,这个类中包含了3个用来注册/注销观察者的方法,分别是:

registerObserver(T observer)

unregisterObserver(T observer)

unregisterAll()


3个方法都是针对Observable<T>中一个用来“存储”观察者们的集合进行操作,这个集合是Observable<T>的一个属性:

protected final ArrayList<T> <span style="color:#FF0000;">mObservers</span> = new ArrayList<T>();


那么Observable<DataSetObserver>中的DataSetObserver又是什么类呢:

public abstract class DataSetObserver {

    public void onChanged() {

    }

    public void onInvalidated() {

    }

}


这是一个抽象类,它定义了两个空方法(但不是抽象方法)。关于这个类的说明主要包括两点:

1)当(被观察者内部的)数据集发生改变或不可用时用来接收回调。典型的数据集有像被观察的Cursor或者Adapter

2)任何加入到DataSetObservable中的对象都必须是该类的实现类对象。

其中第2点的完整说法应该是加入到DataSetObservablemObservers中的对象,都必须要继承DataSetObserver并应该重写其中的空方法。原因很简单,看一下DataSetObservablenotifyChanged方法就知道:

public void notifyChanged() {

        synchronized(mObservers) {

            for (int i = mObservers.size() - 1;i >= 0; i--) {

                mObservers.get(i).onChanged();

            }

        }

    }


mObserversDataSetObservable的父类Observable用来“存储”观察者们的集合。而DataSetObservablenotifyChanged方法实际就是在调用每一个观察者的(或者说DataSetObserver实现者)的onChanged方法。

OK,现在知道了ArrayAdapternotifyDataSetChanged方法最终是触发了父类BaseAdapter的一个属性mDataSetObservablenotifyChanged方法,该方法会遍历mObservers中的每一个DataSetObserver,并调用它们的onChange方法。那么ArrayAdaptermDataSetObservable是什么时候添加的DataSetObserver呢?是在ListView/GridView调用setAdapter方法的时候。看一下ListViewsetAdapter方法:

publicvoid setAdapter(ListAdapter adapter) {

        if (mAdapter != null &&mDataSetObserver != null) {

            mAdapter.unregisterDataSetObserver(mDataSetObserver);

        }

        resetList();

        mRecycler.clear();

        if (mHeaderViewInfos.size() > 0||mFooterViewInfos.size() > 0) {

            mAdapter = newHeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);

        }else {

            mAdapter = adapter;

        }

        mOldSelectedPosition =INVALID_POSITION;

        mOldSelectedRowId = INVALID_ROW_ID;

        // AbsListView#setAdapter will updatechoice mode states.

        super.setAdapter(adapter);

        if (mAdapter != null) {

            mAreAllItemsSelectable =mAdapter.areAllItemsEnabled();

            mOldItemCount = mItemCount;

            mItemCount = mAdapter.getCount();

            checkFocus();

           <span style="color:#FF0000;"> mDataSetObserver = new AdapterDataSetObserver();

           mAdapter.registerDataSetObserver(mDataSetObserver);</span>

           mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());

            int position;

            if (mStackFromBottom) {

                position = lookForSelectablePosition(mItemCount- 1, false);

            } else {

                position =lookForSelectablePosition(0, true);

            }

            setSelectedPositionInt(position);

           setNextSelectedPositionInt(position);

            if (mItemCount == 0) {

                // Nothing selected

                checkSelectionChanged();

            }

        } else {

            mAreAllItemsSelectable = true;

            checkFocus();

            // Nothing selected

            checkSelectionChanged();

        }

       <span style="color:#FF0000;"> requestLayout();</span>

}


可以看到里面有两行代码:

mDataSetObserver= new AdapterDataSetObserver();

mAdapter.registerDataSetObserver(mDataSetObserver);


先看一下AdapterDataSetObserver类的内容:

class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver{

        @Override

        public void onChanged() {

            super.onChanged();

            if (mFastScroller != null) {

               mFastScroller.onSectionsChanged();

            }

        }

        @Override

        public void onInvalidated() {

            super.onInvalidated();

            if (mFastScroller != null) {

               mFastScroller.onSectionsChanged();

            }

        }

}


它继承自AdapterView<ListAdapter>.AdapterDataSetObserver并且在onChangedonInvalidated方法中均调用了父类的同名方法,因此再看一下AdapterView<ListAdapter>.AdapterDataSetObserver的内容:

class AdapterDataSetObserver<span style="color:#FF0000;"> extends DataSetObserver</span> {

        private Parcelable mInstanceState =null;

        @Override

        public void onChanged() {

            mDataChanged = true;

            mOldItemCount = mItemCount;

            mItemCount =getAdapter().getCount();

            // Detect the case where a cursorthat 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();

           <span style="color:#FF0000;"> requestLayout();</span>

        }

 

        @Override

        public void onInvalidated() {

            //方法的具体实现略…

        }

        public void clearSavedState() {

            mInstanceState = null;

        }

}


AdapterView<ListAdapter>.AdapterDataSetObserver继承了DataSetObserver。这就说明mDataSetObserverDataSetObserver的实现者,可以作为观察者被加入到mObservers中。所以接下来mAdapter.registerDataSetObserver(mDataSetObserver);就是将mDataSetObserver加入到mObervers中的。

看一下registerDataSetObserver方法的源码:

public void registerDataSetObserver(DataSetObserverobserver) {

       mDataSetObservable.registerObserver(observer);

    }


调用mDataSetObservableregisterObserver方法。DataSetObservableregisterObserver方法源码是:

public void registerObserver(T observer) {

        if (observer == null) {

            throw new IllegalArgumentException("Theobserver is null.");

        }

        synchronized(mObservers) {

            if (mObservers.contains(observer)){

                throw newIllegalStateException("Observer " + observer + " is alreadyregistered.");

            }

            <span style="color:#FF0000;">mObservers.add(observer);</span>

        }

}


所以mAdapter.registerDataSetObserver(mDataSetObserver)方法的作用就是将作为DataSetObserver实现者对象的mDataSetObserver添加到了mDataSetObservablemObservers中。这样,当调用了ListViewsetAdapter方法时,实际就是将作为方法参数传入的ArrayAdapter中的一个mDataSetObserver对象添加到了ArrayAdapter中的mDataSetObservable中的mObservers集合中,随着ArrayAdapter调用notifyDataSetChanged方法,就调用的是AdapterView<ListAdapter>.AdapterDataSetObserver重写的DataSetObserver中的onChanged方法。重写的onChanged方法的最后一句requestLayout会发起一个从顶层布局依次往下的重新布局,这个过程最终会调用到ListViewonLayout方法(ListView没有该方法,因此调用的是其父类的AbsListViewonLayout方法):

 

protected void onLayout(boolean changed, intl, int t, int r, int b) {

        super.onLayout(changed, l, t, r, b);

        mInLayout = true;

        if (changed) {

            int childCount = getChildCount();

            for (int i = 0; i < childCount;i++) {

                getChildAt(i).forceLayout();

            }

            mRecycler.markChildrenDirty();

        }

        if (mFastScroller != null &&mItemCount != mOldItemCount) {

           mFastScroller.onItemCountChanged(mOldItemCount, mItemCount);

        }

        <span style="color:#FF0000;">layoutChildren();</span>

        mInLayout = false;

        mOverscrollMax = (b - t) /OVERSCROLL_LIMIT_DIVISOR;

    }


这里会触发layoutChildren方法,这个方法里会完成ListView彻底的布局重绘。源代码较长,就不粘贴了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值