概述
ListView的源码中使用了多种设计模式,我们先来看一下观察者模式的应用。
先来看一张UML图:
从图中可以看到ListView通过setAdapter方法将观察者对象传递到BaseAdapter中,然后BaseAdapter通过registerDataSetObserver()方法框观察者对象加入到mDataSetObservable列表中,而通过调用Adapter的notifyDatasetChanged方法通知观察者进行notifyChanged方法调用,从而进行界面的刷新。
源码分析
先看ListView的setAdapter方法:
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
// AbsListView#setAdapter will update choice mode states.
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
checkFocus();
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
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();
}
requestLayout();
}
mAdapter.unregisterDataSetObserver(mDataSetObserver);
当mAdapter和mDataSetObserver都不为空时,将原来的mDataSetObserver进行反注册,即从观察者列表中去除掉。这种情况一般出现在当我们重复设置Adapter时。
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
这里生成了一个AdapterDataSetObserver对象。
看一下AdapterDataSetObserver的源码:
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();
}
}
}
AdapterDataSetObserver又继承了 AdapterView<ListAdapter>.AdapterDataSetObserver。
这个 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();
}
@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();
}
public void clearSavedState() {
mInstanceState = null;
}
}
到这一步,DataSetObserver终于出现了。经历了千辛万苦最终还是生成的是一个DataSetObserver对象。
这个对象作为一个观察者,我们回到ListView的setAdapter方法中,看到mAdapter调用registerDataSetObserver方法将DataSetObserver对象传递进去。而registerDataSetObserver方法的源码是:
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
这里又调用了Observable中的registerObserver方法,将观察者添加到观察者列表中:
public abstract class Observable<T> {
/**
* The list of observers. An observer can be in the list at most
* once and will never be null.
*/
protected final ArrayList<T> mObservers = new ArrayList<T>();
/**
* Adds an observer to the list. The observer cannot be null and it must not already
* be registered.
* @param observer the observer to register
* @throws IllegalArgumentException the observer is null
* @throws IllegalStateException the observer is already registered
*/
public void registerObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
if (mObservers.contains(observer)) {
throw new IllegalStateException("Observer " + observer + " is already registered.");
}
mObservers.add(observer);
}
}
}
到这里算是将观察者进行注册了。
我们再去看Adapter的notifyDataSetChanged方法:
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
这里调用的是Adapter中的mDataSetObservable的notifyChanged()方法。而DataSetObserval对象的notifyChanged方法则遍历观察者列表然后调用观察者的onChanged方法:
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();
}
}
}
而回到上面AdapterDataSetObserver类的方法中重写了onChanged方法,该方法最终调用的是requestLayout()对界面进行刷新。到这里就全部实现了观察者模式的全部流程。