观察者模式是一个使用频率非常高的模式,他最常用的地方是GUI系统和订阅-发布系统。 该模式的最重要的作用就是解耦,使观察者和被观察者之间依赖尽可能小,甚至好无依赖。
定义对象间一种一对多的关系,使得每当一个对象改版状态,所有依赖它的对象都会得到通知并更新。 如图:
1.事件多级触发场景 2.关联行为场景 3.跨系统的消息交换场景,如:消息队列,事件总线的处理机制
举几个简单的例子说明一下:
Subject:抽象主题,把所有观察者对象的引用保持再一个集合,每个主题可以有多个观察者(一对多)。 ConcreteSubject:具体主题,在内部发生变化是后,通知所有注册过的观察者。 Observer:抽象观察者,定义了一个更新接口,得到主题更改通知的时候更新自己。 ConcreteObserver:具体的观察者,实现了抽象观察者的更新接口,以便在主题状态发生变化时候更新自身状态。
我们假设开发一款新闻的软件,每当有新的内容推出,那么只要是订阅了该新闻的用户都可以接收到该新闻。 这种模式叫做发布–订阅模式,也称为观察者模式。
demo下载地址:http://download.csdn.net/download/github_33304260/10146740
首先我们需要完成被观察者,这里新闻网站是被观察对象。
/**
* Created by doudou on 2017/12/5.
*
* 新闻网站----被观察者
*/
public class News extends Observable{
public void postNewPublication(String content){
//标识状态或者内容发送改变
setChanged();
//通知所有观察者
notifyObservers(content);
}
}
然后去完成观察者:
/**
* Created by doudou on 2017/12/5.
*
* 订阅新闻的用户-----观察者
*/
public class User implements Observer{
public String name;
public MainActivity activity;
private String msg;
public User(String name, MainActivity activity) {
this.name = name;
this.activity = activity;
}
@Override
public void update(Observable observable, Object o) {
String news = "Hi,"+name+",发布新内容啦!!"+o;
Log.e("binli",news);
}
}
接着我们就可以发布新闻啦!
news = new News();
//观察者
user_one = new User("用户一",this);
user_two = new User("用户二",this);
user_three = new User("用户三",this);
news.addObserver(user_one);
news.addObserver(user_two);
news.addObserver(user_three);
news.postNewPublication("重大新闻,新的一期Android技术前线周报发布啦!!!");
Observer和Observable是JDK中的内置类型,可以看出观察者模式的重要性。在这里Observer是抽象的观察者,user是具体的观察者;Observable是抽象的主题,News是具体的主题。
当User订阅了News之后,当News有更新,就会去遍历所有观察者(User),然后给每一个观察者更新信息,即调用User的update()
方法,这样就完成了一对多的通知功能。
在这个过程中,完全依赖Observer和Observable,对于User和News完全没有耦合,保证了订阅的灵活性和可扩展性。
RecycleView最重要的一个功能就是Adapter,当我们向RecycleView中添加数据后,都会调用notifyDataSetChanged()
方法,这是为什么呢,今天来一探究竟。
我们先看adapter.notifyDataSetChanged()
函数
public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild {
//代码省略
public static abstract class Adapter<VH extends ViewHolder> {
private final AdapterDataObservable mObservable = new AdapterDataObservable();
//代码省略
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}
//代码省略
}
//代码省略
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
public boolean hasObservers() {
return !mObservers.isEmpty();
}
/**
* 数据集观察者
*/
public void notifyChanged() {
/**
* 调用每个观察者的onChanged函数来通知他们被观察者发生了变化
*/
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
//代码省略
}
}
从上面的代码我们可以看出来,当我们调用adapter.notifyDataSetChanged()
时,实际在遍历所有的观察者,并调用他们的onChanged方法,从而告诉观察者发生了变化。
那么问题来了,这些观察者从哪里来的?
其实这些观察者是在setAdapter
时候产生的。我们看下相关代码:
public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild {
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();
//代码省略
public void setAdapter(Adapter adapter) {
//代码省略
setAdapterInternal(adapter, false, true);
//代码省略
}
private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
/**
*如果已经有了一个adapter,那么先注销该Adapter的对应的观察者
*/
if (mAdapter != null) {
mAdapter.unregisterAdapterDataObserver(mObserver);
mAdapter.onDetachedFromRecyclerView(this);
}
//代码省略
mAdapterHelper.reset();
final Adapter oldAdapter = mAdapter;
mAdapter = adapter;
if (adapter != null) {
/**
* 将这个观察者注册到Adapter中,实际上是注册到AdapterDataObserver
*/
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);
}
//代码省略
}
//代码省略
private class RecyclerViewDataObserver extends AdapterDataObserver {
/**
* 上面说过调用Adapter的notifyDataSetChanged时调用所有观察者的onChange方法,核心就是在这实现的。
* 重新设置Flag,然后重新跟新布局
*/
@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
if (mAdapter.hasStableIds()) {
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
} else {
mState.mStructureChanged = true;
setDataSetChangedAfterLayout();
}
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}
//代码省略
}
//代码省略
}
到这里我们知道,当RecycleView
数据发生变化时,调用Adapter
的notifyDataSetChanged
函数,该函数会调用AdapterDataObservable
的notifyChanged
函数,这个函数会调用所有观察者(RecyclerViewDataObserver)的onChanged
方法,然后所有观察者会重新绘制布局。
这就是一个观察者模式。