观察者模式和适配器模式都是JAVA中最重要的设计模式。观察者模式可以将回调作为其实现的一种方式,适配器模式本质上就是一个类实现了某接口,同时继承了某父类,即拥有接口和父类的所有成员,这就是“适配”的含义。
在使用ListView的过程中,只要为其传入Adapter即可。由于Android中所有Adapter都继承了BaseAdapter,这里主要研究BaseAdapter。追踪源码,绘制UML图,如图1.
图1,BaseAdapter与ListView的UML类图
BaseAdapter最终实现的是Adapter接口,该接口即包含了最重要的几个函数:
+registerDataSetObserver(DataSetObserver observer):void//注册监听器对象oberver
+unregisterDataSetObserver(DataSetObserver observer):void//解除observer对象
+getCount():int//Adapter中数据的个数
+getItem(intposition):Object//Adapter中每个position的数据
+getItemId(int position):long
+getView(int position, View convertView, ViewGroupparent):view//每个position返回的view
这里注册的监听器对象是DataSetObserver类型,它是一个接口,只有一个方法,即:
+onChanged():void
具体到BaseAdapter,它拥有一个DataSetObservable类型的成员变量,这个成员变量内部:
-mObservers:ArrayList
+unregisterObserver(T observer):void//注册监听器对象oberver
+registerObserver(Tobserver):void/解除observer对象
+notifyChanged():void//通知变更
BaseAdapter(继承至)中有unregisterObserver和registerObserver两个方法,本身有notifyChanged方法,而BaseAdapter的成员变量DataSetObservable也有这三个方法。没错,最终DataSetObserverobserver是注册到BaseAdapter的成员变量DataSetObservable中去的,notifyChanged方法也是调用DataSetObservable的notifyChanged方法。
public abstractclass BaseAdapter implements ListAdapter, SpinnerAdapter {
private final DataSetObservablemDataSetObservable = new DataSetObservable();
……//省略无关内容
public void registerDataSetObserver(DataSetObserverobserver) {
mDataSetObservable.registerObserver(observer);
}
public voidunregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
* Notifies the attached observers that theunderlying data has been changed
* and any View reflecting the data setshould refresh itself.
*/
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
……//省略无关内容
}
BaseAdapter的成员变量DataSetObservable mDataSetObservable又是如何实现注册DataSetObserver observer、解除DataSetObserverobserver、通知DataSetObserver observer呢?这里的注册,即指的是将DataSetObserver observer添加到DataSetObservable中List
这里看一下DataSetObservable的父类Observable
public abstract class Observable {
/**
* The list of observers. An observer can be in the list at most
* once and will never be null.
*/
protected finalArrayList mObservers = new ArrayList();
/**
* Adds an observer to the list.The observer cannot be null and it must not already
* be registered.
* @param observer the observerto register
* @throwsIllegalArgumentException the observer is null
* @throws IllegalStateExceptionthe observer is already registered
*/
public void registerObserver(Tobserver) {
if (observer == null) {
throw newIllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
if(mObservers.contains(observer)) {
throw newIllegalStateException("Observer " + observer + " is alreadyregistered.");
}
mObservers.add(observer);
}
}
/**
* Removes a previouslyregistered observer. The observer must not be null and it
* must already have beenregistered.
* @param observer the observerto unregister
* @throwsIllegalArgumentException the observer is null
* @throws IllegalStateExceptionthe observer is not yet registered
*/
public void unregisterObserver(Tobserver) {
if (observer == null) {
throw newIllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
int index =mObservers.indexOf(observer);
if (index == -1) {
throw newIllegalStateException("Observer " + observer + " was notregistered.");
}
mObservers.remove(index);
}
}
/**
* Remove all registeredobservers.
*/
public void unregisterAll() {
synchronized(mObservers) {
mObservers.clear();
}
}
}
再看一下DataSetObservable本身,notifyChanged()通知所有观察者在这里实现。
public class DataSetObservable extends Observable {
/**
* Invokes {@linkDataSetObserver#onChanged} on each observer.
* Called when the contents ofthe data set have changed. The recipient
* will obtain the new contentsthe next time it queries the data set.
*/
public void notifyChanged() {
synchronized(mObservers) {
// since onChanged() isimplemented by the app, it could do anything, including
// removing itself from{@link mObservers} - and that could cause problems if
// an iterator is usedon the ArrayList {@link mObservers}.
// to avoid suchproblems, just march thru the list in the reverse order.
for (int i =mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
/**
* Invokes {@linkDataSetObserver#onInvalidated} on each observer.
* Called when the data set isno longer valid and cannot be queried again,
* such as when the data set hasbeen closed.
*/
public void notifyInvalidated(){
synchronized (mObservers) {
for (int i =mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}
一句话总结BaseAdapter:BaseAdapter将注册、解除注册、通知观察者的事件都委托给了内部的成员变量DataSetObservablemDataSetObservable,而DataSetObservable mDataSetObservable对于观察者的管理是通过链表进行的。
通过setAdapter(Tadapter)方法将Adapter实例传入AdapterView
首先明确,监听者的任务是什么。Adapter数据改变,观察者应该提示AdapterView
查看AdapterView
public abstract class AdapterView 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();//View中的函数,用于重新绘制View
}
……//省略无关内容
}
最后,查看一下ListView的setAdapter(Adapter adapter)。这里应该会将ListView的内部类实现的观察者注册到传入的Adapter adapter,并第一次绘制ListView。
public classListView extends AbsListView {
……//省略无关内容
public void setAdapter(ListAdapter adapter){
if (mAdapter != null &&mDataSetObserver != null) {//内部已经有Adapter,且观察者不为null,则去除观察者
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();//清空List
mRecycler.clear();//清空缓存的view
if (mHeaderViewInfos.size() > 0||mFooterViewInfos.size() > 0) {//ListView的头尾部分view
mAdapter = newHeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);//封装传入新的adapter
} else {
mAdapter = adapter;//直接传入新的adapter
}
mOldSelectedPosition =INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
// AbsListView#setAdapter will updatechoice mode states.
super.setAdapter(adapter);
if (mAdapter != null) {//根据Adapter重新计算相关属性
mAreAllItemsSelectable =mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();//个数
checkFocus();
mDataSetObserver = newAdapterDataSetObserver();//生成新的监听者
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();//重新绘制
}
……//省略无关内容
}
ListView中有个内部类AdapterDataSetObserver,其OnChange()方法是通过计算Adapter来重绘ListView的。
ListView传入Adapter后,将AdapterDataSetObserver注册到Adapter,即添加到Apdater内部的DataSetObservable(链表类型),并第一次绘制ListView。
当Apapter数据源变化后,通知Adatpter notify即遍历了DataSetObserver的链表,并调用了AdapterDataSetObserver的onChange()函数,即重绘了ListView。
注意,由于Apdater内部的DataSetObservable是链表类型,所以,可以注册多个监听者,即多个ListView可以绑定同一个Adapter,数据源变化后会通知所有ListView。
最后,我认为,适配器模式在这里并没有特别体现(参考2,适配器即Adapter继承/某接口,实现某个类),而着重体现了观察者模式。
参考1:【安卓笔记】数据适配器(adapter)中的观察者模式,http://m.blog.csdn.net/blog/RowandJJ/42293681
参考2:Android源码之ListView的适配器模式,http://www.2cto.com/kf/201502/378700.html