上一篇 EventBus设计模式剖析(二)建造者模式
EventBus:
由开源组织greenrobot开发的事件发布-订阅总线库。
设计模式:
软件开发中问题的解决套路。
观察者模式简介
定义:定义对象间一种一对的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到广播通知并被自动更新。
其实观察者模式(Observer Pattern)叫做发布-订阅模式更合适。发布者一旦更新消息,所有订阅者都能收到。观察者模式也很适用于UI事件触发和侦听,消息交换等场景
Observer和Observable是JDK中的内置类型,若一个对象继承了Observer类,那么这段代码大概率用了观察者模式。
EventBus类中的观察者模式
EventBus作为事件发布-订阅总线库,必然使用了发布-订阅模式。
继续使用之前文章的代码分析做分析。EventBus类通过register()方法注册成为订阅者(观察者)。
// 1 注册广播
EventBus.getDefault().register(EventBusActivity.this);
EventBus通过post()方法进行发布,即拿到EventBus.getDefault()的线程自动成为发布者(被观察者)。EventBus以单例模式创建,就会变成长期跟随在这个Android应用的事件收发中心,贯穿全局。
// 4 发送消息
EventBus.getDefault().post(new MessageEvent("主线程发送过来的数据"));
现在我们来看看如何register(注册)和如何post(发布)的。
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final SubscriberMethodFinder subscriberMethodFinder;
EventBus(EventBusBuilder builder) {
//以事件类的class对象为键值,记录注册方法信息,值为一个Subscription的列表
subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList<Subscription>>();
//以注册的类为键值,记录该类所注册的所有事件类型,值为一个Event的class对象的列表
typesBySubscriber = new HashMap<Object, List<Class<?>>>();
}
// 注册给定的订阅服务器以接收事件,false表示不是粘性事件。
public void register(Object subscriber) {
register(subscriber, false, 0);
}
// 注册给定的订阅服务器以接收事件,并指定阅者优先级,从而影响事件交付顺序,false表示不是粘性事件。
public void register(Object subscriber, int priority) {
register(subscriber, false, priority);
}
// 同步方法,只能单线程访问,直到该线程释放同步锁,下一线程才可以访问
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); // 订阅方法集合
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority); // 订阅函数
}
}
// 必须在同步块中调用
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
Class<?> eventType = subscriberMethod.eventType; // 获取订阅方法的事件类
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); // // 创建订阅类 subscriptions集合,内部子项Subscription
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority); // new一个我们想要添加的 Subscription
// 获取订阅了此事件类的所有订阅者信息列表,如果不存在则将其加入订阅者信息列表,如果已经存在此订阅者信息则抛出已注册的异常
if (subscriptions == null) { // subscriptions集合为空
subscriptions = new CopyOnWriteArrayList<Subscription>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) { // 若集合中已经有newSubscription,不必注册了,抛出异常
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "+ eventType);
}
}
int size = subscriptions.size(); // subscriptions集合大小
for (int i = 0; i <= size; i++) { // 遍历,若优先级较高,则插入;若优先级最低(i == size),尾部插入。
if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); // 获取此订阅者实例订阅的所有事件类的列表
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<Class<?>>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType); // 将此事件类加入 订阅者事件类列表中
......
}
订阅过程是在维护两个Map,一个是subscriptionsByEventType,另外一个是typesBySubscriber。首先来说subscriptionsByEventType:
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
subscriptionsByEventType内部结构是Map<事件类,该事件的所有订阅者>。
private final Map<Object, List<Class<?>>> typesBySubscriber;
typesBySubscriber内部结构是Map<订阅者,该订阅者所订阅的所有事件>。
其实这两个对象结构不同,但是所存储的信息是完全一致的。那为什么要重复定义呢?
因为EventBus是一个发布订阅系统,subscriptionsByEventType是从发布者角度订制,而typesBySubscriber是从订阅者角度订制。
基于观察者模式构建的其他代码
1、Android的BroadcastRecevier广播机制
2、ListView中的notifyDataSetChanged()方法
参考文献
1、设计模式|菜鸟教程:https://www.runoob.com/design-pattern/design-pattern-tutorial.html
2、《Android源码设计模式解析与实战》何红辉,关爱民著
3、蕉下孤客:https://www.jianshu.com/p/1b68ace4600a
4、野生的安卓兽:https://www.jianshu.com/nb/10598547
网友评论