在android的开发过程中,观察者模式是一个使用非常频繁的模式,而且在很多的源码当中也可以找到他们的身影,这个模式的一个重要作用就是解耦,将被观察者和观察者进行解耦,使得它们之间的依赖性更小,也有利于代码的维护和扩展。
定义
定义对象间一种一对多的依赖关系,使得每当一个对象状态发生改变,则所有依赖于它的对象都会得到通知并被自动更新
使用场景
1》关联行为场景,需要注意的是,关联行为是可拆分的,而不是"组合"关系
2》事件多级触发场景
3》跨系统的消息交换场景,如消息队列,事件总线的处理机制
Java中的观察者模式
/**
* 观察者
*/
public class RealObserver implements Observer {
public String mName;
public RealObserver(String name) {
this.mName = name;
}
@Override
public void update(Observable o, Object arg) {
System.out.println(mName+"更新内容了,快来看看吧");
}
}
/**
* 被观察者
*/
public class RealObservable extends Observable {
public void addNewContent(String content) {
setChanged();
notifyObservers(content);
}
}
public class Test {
public static void main(String[] args) {
// 被观察者
RealObservable realObservable = new RealObservable();
// 观察者
RealObserver realObserver = new RealObserver("泡沫之夏");
RealObserver realObserver1 = new RealObserver("会有天使替我爱你");
RealObserver realObserver2 = new RealObserver("黎明前的黑暗");
// 将观察者注册到可观察对象的观察者列表中
realObservable.addObserver(realObserver);
realObservable.addObserver(realObserver1);
realObservable.addObserver(realObserver2);
// 发布消息
realObservable.addNewContent("有新内容进行更新了");
}
}
最后的输出结果是:
那么现在我们先来看看Java中的观察者模式的源码,看看它里面到底是怎么执行的
首先我们来看观察者Observer
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
非常简单,只是一个接口,里面有一个update方法,但是请稍微留意一下这两个参数,第一个参数代表的是具体的哪个观察者对象,第二个参数代表的是更新的内容
接下来我们来看看被观察者,即Observable
public class Observable {
// 是否需要发生更新通知
private boolean changed = false;
// 集合:继承了AbstractList,实现了List;所以,它是一个队列,支持相关的添加、删除、修改、遍历等功能
// 用来保存所有的观察者
private Vector<Observer> obs;
public Observable() {
obs = new Vector<>();
}
// 添加观察者
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
// 移除观察者
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
// 给所有的观察者发送通知(发送的内容信息为空)
public void notifyObservers() {
notifyObservers(null);
}
// 遍历所有的观察者,并发送通知
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!hasChanged())
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
// 删除所有的观察者
public synchronized void deleteObservers() {
obs.removeAllElements();
}
// 设置通知状态
protected synchronized void setChanged() {
changed = true;
}
// 清除通知状态
protected synchronized void clearChanged() {
changed = false;
}
// 获取通知状态
public synchronized boolean hasChanged() {
return changed;
}
// 获取观察者对象的数量
public synchronized int countObservers() {
return obs.size();
}
}
被观察者的源码也非常简单,就是使用一个集合来保存观察者对象,然后提供了对观察者对象的增删的方法,最后提供了一个方法用来循环遍历所有的观察者对象并触发update()方法
Android中的观察者模式
在android开发过程中,ListView是一个非常好用的控件,尽管它现在已经被RecyclerView所代替,但是这并不影响我们对于它的源码的分析。今天,我们就通过分析ListView来加深对观察者模式的理解。我们知道,在更新数据的时候我们只需要一行代码notifyDataSetChanged()方法就可以搞定,那么我们先来看看这行代码做了什么
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
// 数据集观察者
private final DataSetObservable mDataSetObservable = new DataSetObservable();
private CharSequence[] mAutofillOptions;
public boolean hasStableIds() {
return false;
}
// 将观察者添加到被观察者的列表中
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
// 将观察者从被观察者的列表中移除
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
// 通知所有的观察者
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
// 省略代码
}
可以看到,对于ListView而言,在其内部也是通过观察者模式来通知界面进行更新的,当我们调用notifyDataSetChanged()方法的时候,会调用被观察者的notifyChanged()方法,那么我们来看看notifyChanded()方法做了什么
public class DataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
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();
}
}
}
}
可以看到,notifyChanged()方法也很简单,就是对所有的观察者对象进行遍历执行onChanged()方法
那么现在就有一个疑问了,我们的观察者是从哪里来的呢?这个时候我们就需要看看当我们setAdapter()的时候里面做了啥
@Override
public void setAdapter(ListAdapter adapter) {
// 如果已经有了一个adapter,那么先注销该adapter对应的观察者
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
}
// 代码省略
super.setAdapter(adapter);
if (mAdapter != null) {
mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
mOldItemCount = mItemCount;
// 获取数据的数量
mItemCount = mAdapter.getCount();
checkFocus();
// 注册一个数据集观察者
mDataSetObserver = new AdapterDataSetObserver();
// 将观察者注册到adapter中
mAdapter.registerDataSetObserver(mDataSetObserver);
// 代码省略
} else {
// 代码省略
}
// 更新界面
requestLayout();
}
从上面可以看出,在设置Adapter时会构建一个AdapterDataSetObserver,也就是观察者,最后,将这个观察者注册到Adapter中,这样我们的被观察者,观察者都有了。那么,AdapterDataSetObserver又是什么呢?我们来看看
AdapterDataSetObserver是在AbsListView里面
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();
}
}
}
而它又继承自AbsListView的父类AdapterView的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();
}
到这里我们就知道了,总结一下:
1.AdapterView里面有一个内部类AdapterDataSetObserver,在ListView设置adapter的时候会构建一个AdapterDataSetObserver并且注册到Adapter中
2.在Adapter中包含一个数据集可观察者DataSetObservable,在数据数量发生改变时,开发者手动调用Adapter.notifyDataSetChanged,而notifyDataSetChanged实际上会调用DataSetObservable函数,该函数会遍历所有观察者的onChanged()函数
3.在AdapterDataSetObserver的onChanged函数中获取Adapter中数据集的新数量,然后调用ListView的requestLayout()方法重新进行布局,更新用户界面
到这里,我们的观察者模式就分析完毕了,欢迎大家在下面留言