说在前面的话:
EventBus相信大家已经不陌生了,主要功能是替代Intent、Handler、BroadCast在各组件、线程之间传递消息。他的最牛逼优点是开销小,代码简洁,解耦代码。,因此怎么使用就不在此叙述,此文主要是通过全局设计去理解设计框架,来咱们开始吧~
上图是官方给的,从这个图中咱们就能知道是基于观察者模式架构,所以具备3个要素
Event:事件
Subscriber:事件订阅者,接收特定的事件。
Publisher:事件发布者,用于通知Subscriber有事件发生。
「我们从创建来看:」
static volatile EventBus defaultInstance;
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
用双判单例模式生成实例:
这里用两次判断,是解决多线程并发问题,但由于执行defaultInstance = new EventBus();并非是一个原子性操作,关键执行以下步骤
1.给EventBus实例分配内存空间
2.初始化EventBus的构造器
3.将defaultInstance指向分配的内存空间(此时非null)
但是,由于Java编译器允许处理器乱序执行(out-of-order),以及JDK1.5之前JMM(Java Memory Medel)中Cache、寄存器到主内存回写顺序的规定,上面的第二点和第三点的顺序是无法保证的,也就是说,执行顺序可能是1-2-3也可能是1-3-2,如果是后者,并且在3执行完毕、2未执行之前,被切换到线程二上,这时候defaultInstance因为已经在线程一内执行过了第三点,defaultInstance已经是非空了,所以线程二直接拿走defaultInstance,然后使用,然后报错,在JDK1.5之后,官方已经注意到这种问题,因此调整了JMM、具体化了volatile关键字,还是建议使用内部类方式,利用jvm机制保证单例.
这里有说明volatile作用 http://www.cnblogs.com/zhaoliu/p/5389972.html
build建造者模式
这里单例方法上注释说是为方便app获取这个实例,因为在EventBus构造函数中,使用建造者模式来配置生成此实例,
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap, CopyOnWriteArrayList>();
typesBySubscriber = new HashMap
但是不是所有元素都通过EventBusBuilder 来生成,在builder中是一些可自定义配置,公共必须要有的成员放在构造方法中生成
EventBus类
1.事件订阅者:
我们知道在观察者模式中,要想成为订阅者,需要实现接口成为订阅者,当发布者有信息发布是会遍历所有订阅者并回调方法通知订阅者,而EventBus则利用固定4种方法名称 + 参数类型来作为他的不同功能的消息回调方法,这样做的好处是订阅者不用另外实现接口,更简洁。缺点是当接受消息过多时,造成方法混乱和数量多,不利于维护,所以在3.0版本改用注解来实现此功能,这个会在另外一篇文章中详解.
我们在开发中要想使我们具体某一个类接受消息是通过注册 ( EventBus.getDefault().register(this) )成为一个事件订阅者:我们通过具体代码来看看怎么实现的:
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
注册最后都会调用此方法:首先是subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()),subscriberMethodFinder这个类的核心职责就是把订阅者中的约定方法全都找出来,存到map中
private static final Map> methodCache = new HashMap>();
List findSubscriberMethods(Class> subscriberClass) {
String key = subscriberClass.getName();
List subscriberMethods;
synchronized (methodCache) {
subscriberMethods = methodCache.get(key);
}
if (subscriberMethods != null) {
return subscriberMethods;
}
subscriberMethods = new ArrayList();
Class> clazz = subscriberClass;
HashSet eventTypesFound = new HashSet();
StringBuilder methodKeyBuilder = new StringBuilder();
while (clazz != null) {
String name = clazz.getName();
if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
// Skip system classes, this just degrades performance
break;
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
ThreadMode threadMode;
if (modifierString.length() == 0) {
threadMode = ThreadMode.PostThread;
} else if (modifierString.equals("MainThread")) {
threadMode = ThreadMode.MainThread;
} else if (modifierString.equals("BackgroundThread")) {
threadMode = ThreadMode.BackgroundThread;
} else if (modifierString.equals("Async")) {
threadMode = ThreadMode.Async;
} else {
if (skipMethodVerificationForClasses.containsKey(clazz)) {
continue;
} else {
throw new EventBusException("Illegal onEvent method, check for typos: " + method);
}
}
Class> eventType = parameterTypes[0];
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(methodName);
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
if (eventTypesFound.add(methodKey)) {
// Only add if not already found in a sub class
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
}
}
} else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."
+ methodName);
}
}
}
clazz = clazz.getSuperclass();
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
+ ON_EVENT_METHOD_NAME);
} else {
synchronized (methodCache) {
methodCache.put(key, subscriberMethods);
}
return subscriberMethods;
}
}
此处缓存key是订阅者对象 value是SubscriberMethod集合
解析过程
1.如果缓存methodCache中有此订阅者对象,返回;
2.反射获取所有申明的方法
检查是否是约定方法
if (modifierString.length() == 0) {
threadMode = ThreadMode.PostThread;
} else if (modifierString.equals("MainThread")) {
threadMode = ThreadMode.MainThread;
} else if (modifierString.equals("BackgroundThread")) {
threadMode = ThreadMode.BackgroundThread;
} else if (modifierString.equals("Async")) {
threadMode = ThreadMode.Async;
}
符合条件的会增加到集合中
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
此处有一个判断,断点methodKey = "onEventBackgroundThread>leon.trainingproject.AnyEventType"
if (eventTypesFound.add(methodKey)) {
// Only add if not already found in a sub class
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
}
这里eventTypesFound是一个HashSet,作用是利用HashSet不能有重复key值功能,过滤订阅者中父类和子类有方法重写的情况,EventBus只当做一个处理.
此时已经找到约定方法,然后调用
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
Class> eventType = subscriberMethod.eventType;
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// subscriberMethod.method.setAccessible(true);
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
subscriptions.add(i, newSubscription);
break;
}
}
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
if (sticky) {
Object stickyEvent;
synchronized (stickyEvents) {
stickyEvent = stickyEvents.get(eventType);
}
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here.
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}
}
此方法前半部分实现了注册功能,后半部分是如果有sticky事件,则立即响应事件的功能.
核心就是
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
集合记录了事件和订阅者,key是订阅的事件Event,value是订阅此事件的订阅者集合