1.post方法源码分析
先上源码
public void post(Object event) {
//PostingThreadState 保存着事件队列和线程状态信息
PostingThreadState postingState = currentPostingThreadState.get();
//获取事假队列,并将当期事件插入事件队列
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
//此处标记,当前postingState所在线程,即发送事件线程是否是主线程,这个标记与事件订阅的ThreadMode有关
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
//处理队列中的所有事件,
//将所有的事情交给postSingleEvent处理,并移除该事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
postingState是一个ThreadLocal变量,每个Thread有一个,里面有一个集合eventQueue里面存储了当前线程发送的事件对象,调用post时将该线程的postingState对象取出,然后再postingState的事件队列(eventQueue)里添加当前事件,判断当前postingState是否正在发送事件,如果正在发送则不进行处理,如果没有发送则进行发送,而发送的过程其实就是开启了一个while循环,当前事件集合不空则不算取出第一个事件进行处理,处理方法就是postSingleEvent()
postSingleEvent源码
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//发送事件的事件类型
Class<?> eventClass = event.getClass();
//订阅对象是否找到的标记
boolean subscriptionFound = false;
//是否支持事件继承,默认为true,如果订阅了父类型,当发送子类型事件实也会调用其相关订阅方法
if (eventInheritance) {
//找到所有的父类型
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));
}
}
}
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//上一篇文章讲的,该类型的所有 订阅(Subscription)的集合
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;
}
其实总结起来就是找到,找到当前订阅事件的所有注册订阅,然后将当前订阅事件发送给所有的订阅者,postToSubscription进行的处理与上一篇一样,就会最后找到该订阅的订阅对象和订阅方法,通过反射调用该对象的订阅方法,则相当于将事件发送到了订阅者手里
2.postSticky方法
postSticky方法的源码非常简单
public void postSticky(Object event) {
synchronized (stickyEvents) {
//将该粘性事件加入到粘性事件map中,留待将来的注册者注册时处理
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
//像普通事件一样发送给已经订阅的订阅者
post(event);
}
就是将当前粘性事件保存下来,等后面注册该粘性事件的订阅者注册时发送给他,同时将该事件像发送普通事件一样发送给之前订阅了当前事件的订阅者
总结:
- post
- 找到当前线程的发布事件队列,将当前事件对象加入到队列中
- 如果当前线程为开始发布,则开启while循环,将队列中的所有事件发布,若已经在发布中了则不用理会
- 事件发布先根据当前事件类型找到其所有订阅信息(包含订阅者和订阅方法)集合,然后对集合中所有订阅信息进行事件发布
- 每个订阅信息的事件发布根据不同的threadMode切换到不同线程,通过反射调用订阅信息里的调用者的订阅方法
- postSticky
- 将当前粘性事件保存下来,等后面注册该粘性事件的订阅者注册时发送给他
- 调用post发送事件