EventBus3.0源码解析-01这篇文章简单的介绍了EventBus的使用流程,我们知道EventBus有三个主要入口方法,分别为
-
EventBus.getDefault().register(Object);
-
EventBus.getDefault().unregister(Object);
-
EventBus.getDefault().post(Object);
EventBus3.0源码解析-02这篇文章已经介绍了register的逻辑,本文将介绍post,unregister以及sticky事件的逻辑。
Post
post方法的实现如下:
public void post(Object event) {
// 线程安全的变量
PostingThreadState postingState = currentPostingThreadState.get();
// 事件队列
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
// 是否当前线程正在发送事件,如果正在发送事件,那么队列的事件都会处理,这里直接返回就行
if (!postingState.isPosting) {
// 当前线程是否是主线程
postingState.isMainThread = isMainThread();
// 当前线程是否正在发送事件的标识
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
// 遍历队列里面的每个事件
while (!eventQueue.isEmpty()) {
// 单个事件具体处理逻辑
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
// 重置标志
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
post方法里面的大多数逻辑通过看代码注释就能明白,我们这里主要介绍它的核心方法postSingleEvent(Object event, PostingThreadState postingState),该方法的实现如下:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// 是否考虑事件类的继承,默认false
if (eventInheritance) {
// 找到eventClass以及eventClass的父类以及接口
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
// 处理每个事件
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
// 处理事件
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
postSingleEvent方法的实现逻辑为,首先判断是否考虑事件类的继承,如果不考虑,则只通知订阅该event的方法。如果考虑事件类的继承,则会通知订阅该event以及该event的父类以及其实现的接口的所有方法。我们看一下postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass)方法的实现:
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;
}
该方法就是找到订阅了eventClass的所有订阅方法,然后通过postToSubscription(Subscription subscription, Object event, boolean isMainThread)通知订阅方法执行:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
invokeSubscriber方法就是通过反射执行相应的订阅方法,各个ThreadMode的具体含义可以参考这篇文章。
Unregister
unregister方法的实现如下:
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
这个方法的实现非常简单,就是将该订阅类的订阅信息从subscriptionsByEventType和typesBySubscriber变量中剔除。
Sticky事件
sticky事件的使用分为两步:
1、调用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);
}
该方法首先将sticky事件保存在stickyEvents变量中,然后走正常的post事件流程。
2、当我们调用EventBus的register方法时,会执行以下逻辑:
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);
}
如果不考虑事件类的继承关系,那么只是把stickyEvents中eventType拿出来进行通知,如果考虑继承,那么需要把stickyEvents中eventType以及eventType的子类事件都拿出来进行通知。checkPostStickyEventToSubscription方法就是调用上面介绍的postToSubscription方法。
如果大家看完我的本系列文章之后,对EventBus还有不明白的地方,请下载EventBus源码进行学习。