观察者模式Observer Design Pattern)也被称为发布订阅模式Publish-Subscribe Design Pattern

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。

一般情况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。

1 观察者模式 UML

图片来源于《Android 源码设计模式解析与实战》

  • Subject:抽象主题,也就是被观察(Observable)的角色,抽象主题角色把所有观察者对象的引用保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
  • ConcreteSubject:具体主题,该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发出通知,具体主题角色又叫做具体被观察者(Concrete Observable)角色。
  • Observer:抽象观察者,该角色是观察者的抽象类,它定义了一个更新接口,使得在得到主题的更改通知时更新自己。
  • ConcreteObserver:具体的观察者,该角色实现抽象观察者角色所定义的更新接口,以便在主题的状态发生变化时更新自身的状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public interface Subject {
void registerObserver(Observer observer);

void removeObserver(Observer observer);

void notifyObservers(Message message);
}

public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();

@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}

@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObservers(Message message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}

public interface Observer {
void update(Message message);
}

public class ConcreteObserverOne implements Observer {
@Override
public void update(Message message) { //TODO: 获取消息通知,执行自己的逻辑...
System.out.println("ConcreteObserverOne is notified.");
}
}

public class ConcreteObserverTwo implements Observer {
@Override
public void update(Message message) { //TODO: 获取消息通知,执行自己的逻辑...
System.out.println("ConcreteObserverTwo is notified.");
}
}

ConcreteSubject subject = new ConcreteSubject();
subject.registerObserver(new ConcreteObserverOne());
subject.registerObserver(new ConcreteObserverTwo());
subject.notifyObservers(new Message());

2 Android 源码分析 notifyDataSetChanged

这次分析的是 AdapternotifyDataSetChanged ,最终调用的是 RecyclerView.AdapternotifyDataSetChanged 如下:

1
2
3
public final void notifyDataSetChanged() {
mObservable.notifyChanged();
}

这里的 mObservableAdapterDataObservable 进入到 norifyChanged() 方法中。

1
2
3
4
5
6
7
8
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
//...
public void notifyChanged() {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
//...

这里遍历了所有的观察者,并且调用它们的 onChanged 方法。这里的 mObservers 是父类中的一个 ArrayList<T> ,并且有一个 register 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class Observable<T> {

protected final ArrayList<T> mObservers = new ArrayList<T>();

public void registerObserver(T observer) {
if (observer == null) {
throw new IllegalArgumentException("The observer is null.");
}
synchronized(mObservers) {
if (mObservers.contains(observer)) {
throw new IllegalStateException("Observer " + observer + " is already registered.");
}
mObservers.add(observer);
}
}
//...

RecyclerView 中调用 registerObserver 的地方是 RecyclerView.AdapterregisterAdapterDataObserver

1
2
3
public void registerAdapterDataObserver(@NonNull AdapterDataObserver observer) {
mObservable.registerObserver(observer);
}

这是在 setAdapter 中的 setAdapterInternal 中调用的

1
2
3
4
5
6
7
8
9
10
11
 private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();  

private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious,
boolean removeAndRecycleViews) {
//...
if (adapter != null) {
adapter.registerAdapterDataObserver(mObserver);
adapter.onAttachedToRecyclerView(this);
}
//...
}

这里的 mObserverRecyclerViewDataObserver ,然后查看 RecyclerViewDataObserver 中的 onChanged 方法,这就是之前遍历的实现方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private class RecyclerViewDataObserver extends AdapterDataObserver {
RecyclerViewDataObserver() {
}

@Override
public void onChanged() {
assertNotInLayoutOrScroll(null);
mState.mStructureChanged = true;

processDataSetCompletelyChanged(true);
if (!mAdapterHelper.hasPendingUpdates()) {
requestLayout();
}
}

这里最终调用了 requestLayout 刷新了 RecyclerView 页面。这!就是一个观察者模式。

总结

  • 首先 setAdapter 会将 RecyclerViewDataObserver 添加到注册列表 mObservers 中。
  • 当我们在调用 norifyChanged() 方法的时候,循环注册列表中的 ObserveronChanged 方法,其实就是调用 RecyclerViewDataObserveronChanged
  • onChanged 会获取新的数据并刷新 RecyclerView 重新布局。

3 Android 源码 Broadcast

Android Broadcast广播机制分析

感谢

设计模式之美

《Android 源码设计模式解析与实战》

以及上文中的链接