多条目控件AdapterView是仿MVC设计模式进行设计的,即AdapterView与数据是分离的,AdapterView并不直接操作数据,而是利用中间件适配器Adapter,实际上,完整的AdapterView显示是三个逻辑部分:AdapterView+Adapter+Data,Adapter相当于MVC中的控制器C,AdapterView相当于MVC中的视图V,顺便说一句,Android程序设计,也是利用MVC控制模式。既然视图与数据是分离的,那么当数据有更新时,视图显然无法自动更新,Adapter必须实时监控数据变化并刷新视图,这里用到的是Observer(观察者模式)。
一、什么是观察者模式
所谓观察者模式,听起来很复杂高大上,实际上响应过程就如同一个点击事件处理过程(实际上也是按照观察者模式处理,但形式上有所改变),比如一个Button和一个监听器,Button就是被观察者(T extends Observable),监听器就是观察者(T extends DataSetObservable),当Button状态发生变化时,被观察者“贱贱”的向观察者发出通知,告知其状态改变,然后观察者做出相应的处理。观察者模式比较容易混淆的就是这个“贱贱”,并不是观察者主动观察得知被观察者发生变化,而是被动的等待再作相应的处理。
为实现观察者模式,Android设计两个抽象类,分别是DataSetObserver及Observable(可观察的,即被观察者),从英文字面上就直观看出谁是观察者,谁是被观察者。下面对此详细介绍。
二、DataSetObserver(观察者)抽象类与Observable(被观察者)抽象类继承体系
1、DataSetObserver
DataSetObserver类的API这样描述:DataSetObserver(观察者)通常设置给Cursor或Adapter,如果数据发生变化则回调该类方法。DataSetObserver类无法单独调用,必须配合DataSetObservable类使用。该类的实例即是Observer,观察者的刷新视图行为是由onChanged以及onInvalidated方法决定的,通常在AdapterView控件,如ListView中继承该类,并通过重写这两个方法,实现针对性的视图刷新。
public abstract class DataSetObserver {
//当被观察的数据发生变化,回调该函数
public void onChanged()
//当被观察的数据失效,回调该函数
public void onInvalidated()
<span style="font-family: FangSong_GB2312; font-weight: bold; background-color: rgb(255, 255, 255);">2、Observable(被观察者)抽象类继承体系</span>
2.1、Observable基类
这是一个抽象基类,该类主要提供对Observer进行注册或解除注册到ArrayList数据集(Observer必须绑定到某个数据集才能监测)。 源码如下:
<pre name="code" class="java">public abstract class Observable<T> {
//观察者列表,不可重复
protected final ArrayList<T> mObservers = new ArrayList<T>();
//注册观察者observer,即将observer添加到mObservers中
public void registerObserver(T observer) {
//解除观察者observer,即将observer从mObservers中移除
public void unregisterObserver(T observer) {
//解除所有的observer,即清空mObservers列表
public void unregisterAll() {
}
2.2、DataSetObservable类
这是一个可实例化类,通常在对ArrayList数据进行更新后,主动调用notifyChanged()函数,若ArrayList数据失效,比如给视图绑定新的数据源等等,调用notifyInvalidated,源码如下:
public class DataSetObservable extends Observable<DataSetObserver> {
//当数据集发生变化,回调数据集每一个观察者DataSetObserver的onChanged函数,通常视图的刷新在onChanged中完成
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
//当数据集失效(比如关闭),回调数据集每一个观察者DataSetObserver的onInvalidated()函数
public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
}
3、小结
DataSetObserver与Observable之间的逻辑关系可以用一张图表示,很明显,被观察通过notifyChanged()与notifyInvalidated()方法通知并调用Observer方法。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2QvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jM2cjN0IzM4ATNycDM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
三、AdapterView控件与Adapter利用观察者模式刷新界面
1、适配器Adapter中与DataSetObserver有关的方法
1.1、adapter中相关源码
//注册一个observer,观察Adapter关联的数据集是否发生变化(如增加、删除等等)
void registerDataSetObserver(DataSetObserver observer);
//取消注册observer
void unregisterDataSetObserver(DataSetObserver observer);
1.2、BaseAdapter中相关源码
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
//获取DataSetObservable()对象
private final DataSetObservable mDataSetObservable = new DataSetObservable();
//注册一个DataSetObserver
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
//取消一个DataSetObserver
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
//通知观察数据集的observers,数据已经发生变化,并且执行与数据相关的视图刷新操作
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
//通知观察数据集的observers,数据已经失效,一旦调用该函数,表明Adapter也已经失效。
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
1.3、小结
Adapter主要是注册一个Observer,然后在数据有变化时,主动调用notifyDataSetChanged()或notifyInvalidated(),而决定数据在出现变化后的行为(主要是onchanged()方法决定),一般需要在AdapterView中进行个性定制。
2、AdapterView中与DataSetObserver有关的方法
2.1、AdapterView
AdapterView中写了一个继承DataSetObserver的内部类AdapterDataSetObserver,主要是重新onChanged(),onInvalidated()方法,以执行AdapterView的刷新视图操作
class AdapterDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
...
}
@Override
public void onInvalidated() {
...
}
}
2.2、ListView
ListView中,主要是setAdapter()方法将适配器Adapter绑定到ListView,并设置Adapter的观察者为AdapterDataSetObserver。
public void setAdapter(ListAdapter adapter) {
mAdapter = adapter;
if (mAdapter != null) {
//注册Adapter的观察者AdapterDataSetObserver
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
}
2.3、小结
AdapterView控件主要定义Observer行为,即Onchanged()和onInvalidated()方法,然后通过Adapter的注册方法registerDataSetObserver()对定制的mDataSetObserver注册。
3、小结
AdapterView中用一个内部类实现了Observer,Adapter中定义了Observable方法,所以AdapterView是观察者,Adapter是被观察者。
AdpaterView与Adapter是通过方法SetAdapter结合起来的,参考ListView的SetAdapter方法(如下),
@Override
public void setAdapter(ListAdapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
resetList();
mRecycler.clear();
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();
}
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
这两行代码将AdapterView(观察者)注册到Adapter(被观察者)中,接下来如果Adapter中的数据发生变化,主动调用 adapter.notifyDataSetChanged()即可实现整个观察者流程。
四、简单Demo
实现长按长按ListView并删除所在项,主要代码如下:
listview.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent,
View view, int position, long id) {
//长按删除并动态更新listview
datas.remove(position);
myAdapter.notifyDataSetChanged();
return false;
}
} );