我们考虑一个实际中比较常见的情况:我们进行数据显示的时候经常会用到ListView,并且会使用到分页加载机制,用于降低网络数据传输的延迟。那么当ListView中的数据改变的时候(比如加载下一页),我们会使用adapter.notifyDataSetChanged()来通知改变数据的显示,那么,这种机制是什么呢?显然,这是使用了“观察者模式”的设计思维。那么,对于GridView 甚至ViewPager是否也适用呢?我们以ListView来分析,慢慢分析...
我们来回顾一下我们使用ListView显示列表的步骤:
listView = (ListView) findViewById(R.id.listView);
adapter = new MyAdapter();//MyAdapter为自定义的Adapter,继承自BaseAdapter
listView.setAdapter(adapter);//给ListView设置自定义的适配器
那么,第三行代码到底做了什么呢?我们来看看源码:(ListView.java)
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
//作者注:是否需要添加HeadView 和 FootView
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewListAdapter(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();
}
可以看出来,其实setAdapter(adapter)做的是注册被观察者。
而当ListView显示的数据增加或者改变的时候,我们会调用adapter.notifyDataSetChanged()通知改变。再来看看notifyDataSetChanged()做了什么事情,查看源码(DataSetObservable.java)
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();//通知观察者更新
}
}
}
但是mObservers是什么呢?继续追踪:/**
* Provides methods for registering or unregistering arbitrary observers in an {@link ArrayList}.
*
* This abstract class is intended to be subclassed and specialized to maintain
* a registry of observers of specific types and dispatch notifications to them.
*
* @param T The observer type.
*/
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); //注册观察者
}
}
...
}
其实mObservers其实是Observable里面的一个成员。然而,到底在什么地方实际进行了onChanged()了?查看源码(AbsListView.java):
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
@Override
public void onChanged() {
super.onChanged();
if (mFastScroller != null) {
mFastScroller.onSectionsChanged();
}
}
...
}
...
}
追踪super.onChanged()方法(AdapterView.java):
public abstract class AdapterView<T extends Adapter> extends ViewGroup {
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();//重新布局
}
}
}
其中requestLayout()进行重新布局,完成数据更新操作。至此,adapter.notifyDataSetChanged()完成了数据的更新了。
下面,我们看看着一系列过程的类图:
我们看到,真正notifyDataSetChanged()是由AdapterDataSetObserver的onChanged()完成的。ListView继承自AbsListView,而GridView则(GridView.java):
public class GridView extends AbsListView {
}
由此,可以断定GridView和ListView师出同门,同样适合上面所述的过程。
当然,如果你想探索的话,也可以研究一下ViewPager.java,看看它是否也是这样的呢?