前言#
因为项目里用到了EventBus,直接就想到了观察者模式。这种模式用的太多了,例如广播的注册,就是典型的观察者模式。
观察者模式最大的好处就是:自己不用时刻关注对方,而是让对方主动通知自己,这样自己省时省力。
举个生活中的例子:
去饭馆吃饭,我点了一个红烧肉盖饭,那我怎么取餐呢?
1、隔一会就去取餐口看一眼。
2、做好了,服务员喊一嗓子,我一听是我点的餐,然后取餐。
很明显第二种更好,这就是观察者模式。
正文#
观察者的概念非常好理解,我画了一个简单的图:
观察者模式主要有几个步骤:
1、观察者在被观察者 登记注册。
2、当观察者发生改变,携带发生改变的信息(Object)通知观察者做相应的处理。
3、观察者自定义处理过程。
其实实现起来也很简单,例如内部有个List,需要通知的时候就遍历一遍:
/**
* Created by li.zhipeng on 2017/8/2.
*
* 完全自定义被观察者
*/
public class MyNormalObserable {
private HashSet observers = new HashSet();
private static MyNormalObserable instance;
private MyNormalObserable() {
}
public static MyNormalObserable getInstance(){
if (instance == null){
instance = new MyNormalObserable();
}
return instance;
}
/**
* 注册观察者
* */
public void register(OnObservableListener listener){
observers.add(listener);
}
/**
* 通知观察者更新
* */
public void notifyChanged(Object object){
Iterator iterator = observers.iterator();
while (iterator.hasNext()){
iterator.next().update(object);
}
}
/**
* 回调的Listener
* */
public interface OnObservableListener{
void update(Object object);
}
}
使用的时候,也非常简单
// 注册观察者,传入了要处理变化的逻辑
MyNormalObserable.getInstance().register(new MyNormalObserable.OnObservableListener() {
@Override
public void update(Object object) {
...
}
});
// 通知观察者发生改变
MyNormalObserable.getInstance().notifyChanged(Object);
Android自带的观察者模式#
刚才只是一个简单的例子,但是里面还有一些细节需要我们去思考处理,举个例子:
如果我们正在遍历观察者通知改变,这个时候添加观察者或者移除观察者,就会出现问题。
当然还有其他问题,例如多线程等等,所以想要编写一个完善的观察者也不是那么简单,不过不用担心,Android内部已经为我们提供了非常棒的观察者模式辅助类:Observable 和 Observer。
Observable:被观察者,提供了通知变化等等的api。
Observer:观察者,需要重写内部的update方法,实现发生变化时的处理。特别提示:这两个类都在java.util包下,如果你使用了RxJava,RxAndroid,注意类所在的包,别弄混了。
首先继承Observable,修改一点小细节:
/**
* Created by li.zhipeng on 2017/8/2.
*
* 自定义观察者
*/
public class MyObservable extends Observable {
/**
* 通知刷新
* */
public void notifyChanged(){
notifyChanged(null);
}
/**
* 通知刷新
* */
public void notifyChanged(Object object){
setChanged();
notifyObservers(object);
}
}
我们这里定义了notifyChanged方法,为什么要这么做呢?直接notifyObservers不就好了吗?
这么做就说明直接使用notifyObservers肯定不行,因为他有一个判断:
public void notifyObservers(Object arg) {
// 这是一个临时的数组,一会会用到
Observer[] arrLocal;
// 这里加了同步锁,防止多线程操作
synchronized (this) {
// 这里做了是否发生改变的判断,是为了防止出现无意义的更新
if (!hasChanged())
return;
// ArrayList转换成一个临时的数组,这样就防止了通知,添加,移除同时发生可能导致的异常
arrLocal = observers.toArray(new Observer[observers.size()]);
// 清楚发生变化的状态
clearChanged();
}
// 通知观察者
for (int i = arrLocal.length-1; i>=0; i--)
arrLocal[i].update(this, arg);
}
先要判断是否发生了改变,否则不通知,这也是防止出现无意义的通知,设置改变的方法就是setChanged,notifyObservers本身有clearChanged,所以这里我们把他俩组合了一下,就完成更新的准备工作了。
使用起来还跟平时一样:
// 注册观察者
register(new Observer() {
@Override
public void update(Observable observable, Object o) {
Log.e("lzp", "update");
}
});
// 通知更新
observable.notifyChanged();
这两个类的源码非常的简单,有兴趣的可以去看一下,不过我很好奇的是,为什么observable里面用的是ArrayList而不是HashSet,这样防止重复注册不就更简单了吗?
总结#
观察者模式就介绍到这里了,可见观察者模式真的是非常方便,这也是EventBus这么火爆的原因,让不同对象之间的通信变得更加简单粗暴。
接下来我们就来写一个EventBus的简易版。