好多分析EventBus的文章,喜欢上来就贴源码,我看了好屡次老是迷迷糊糊的,此次花时间完全整理一下EventBus,发现EventBus核心其实就是三幅图,这三幅图涉及的是三个HashMap表,弄懂这三幅图那么EventBus就懂了。java
先看一段在activity中注册和反注册EventBus的代码。ide
onStart{
EventBus.getDefault().register(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent1(Event1 event) {
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent2(Event2 event) {
}
onStop{
EventBus.getDefault().register(this);
}
复制代码
看上面的代码,注册监听的是activity,称为subscriber,在activity中监听了Event1和Event2两个事件,如今在另外一个位置执行了一段代码:post
EventBus.getDefault().post(new Event1());
复制代码
这个时候,activity中的onEvent1就会收到事件。下面引入第一幅图: 性能
private final Map<Object, List<Class<?>>> typesBySubscriber;
复制代码
EventBus会在对象register时,使用反射机制,遍历对象的方法,将带有@Subscribe标签而且合法的方法加入到typesBySubscriber。typesBySubscriber是HashMap形式,key是注册的对象自己,因为一个注册的对象中可能有多个监听事件,因此value是用list保存的Event。this
看下register方法中如何处理的spa
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
}
复制代码
上面的代码主要作两件事:一、经过反射遍历注册对象的方法,获取其中带有@Subscribe标签的方法而且放在一个列表中,最后以注册对象为key,@Subscribe的方法列表做为value放在HashMap中,就是上图的形式。code
思考cdn
一、为何要将注册监听对象做为key,监听事件列表做为value放在HashMap中? 要弄懂一个问题,EventBus是观察者模式,上面的activity也就是subscribe是订阅者,activity中的event是订阅事件,一个订阅者能够订阅多个事件,移除一个订阅者的监听事件时,应该将其中全部的event的事件移除。 也就是说在反注册的时候,会经过Subsribe来查找到其中全部额event进行反注册。对象
EventBus.getDefault().post(new Event1());
复制代码
的时候全部注册监听了Event1的监听都会要会收到回调,看下subsciption的结构blog
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(Event event) {
}
复制代码
而subsriber就是订阅者好比会在activity的onstart中执行
....
EventBus.getDefault().register(this);
复制代码
那么subsribe就是activity。
思考 为何须要保存Event和subsribe对应的关系表?
这是由于一个Event可能会有被多个subsribe订阅,因此有当执行post(Event)的时候会查找到全部订阅了Event事件的subscribe并调用其中的event方法。下面看下post方法:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
}
复制代码
post和postSticky主要都会调用到上面的方法,上面方法中subscriptionsByEventType.get(eventClass)
就是经过event的类型找上面的表中找到对应的subscriptions进行通知的。
在看第三幅图以前思考一个问题,postSticky究竟是怎么执行的?为何先执行postSticky,后执行register仍是能够监听到event事件? 先看postSticky代码:
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
复制代码
原来执行postSticky的时候会将event.getclass和event保存起来,而后再看下subscribe代码:
if (subscriberMethod.sticky) {
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
复制代码
先判断注册监听的event是否是sticky的若是是就会用stickEvents表中找到stickyEvent若是若是注册的事件event和stickyEvent同样那么就会执行一次postToSubscription方法,也就是调用注册的方法执行。
一、要理解EventBus就要从register,unRegister,post,postSticky方法入手。要理解register实质上是将订阅对象(好比activity)中的每一个带有subscriber的方法找出来,最后得到调用的就是这些方法。订阅对象(好比activity)是一组event方法的持有者。
二、后注册的对象中sticky方法可以收到以前的stickyEvent方法的缘由是EventBus中维护了stickyEvent的hashMap表,在subsribe注册的时候就遍历其中有没有注册监听stickyEvent若是有就会执行一次回调。
一、使用的时候有定义不少event类, 二、event在注册的时候会调用反射去遍历注册对象的方法在其中找出带有@subscriber标签的方法,性能不高。 三、须要本身注册和反注册,若是忘了反注册就会致使内存泄漏