EventBus3.0源码分析(二)post
距离上篇整整两个月了,忙不是借口,反省。
上一篇文章介绍了register
的过程,这篇接着来,一起看看EventBus
发送事件的过程。EventBus
可以通过post
发送普通事件,还可以通过postSticky
发送粘性事件。粘性事件与普通事件的区别在于:当粘性事件发布后,若有订阅者订阅该事件,该订阅者依然能收到最近一个该事件, 这点在上篇最后有提到。有了这个最基本的认识,我们来看看这两个方法的具体实现。
先瞅瞅发送普通事件post
方法的源码
public void post(Object event) {
// 获取当前线程的PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
// 事件队列
List<Object> eventQueue = postingState.eventQueue;
// 添加到事件队列中
eventQueue.add(event);
// 如果没有发送事件,则将事件队列中的事件一一发送出去
if (!postingState.isPosting) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
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的流程:先获取当前调用post
方法的PostingThreadState
,并将该事件添加到事件队列中,如果当前没有发送事件, 则通过postSingleEvent
方法将队列中的事件一一发送出去。
继续分析postSingleEvent
方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
// 获取该事件的class
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// 是否支持事件继承(默认是支持的)
if (eventInheritance) {
// 查找所有跟eventClass相关的类(包括eventClass实现的接口以及父类)
// 若是第一次发送eventClass,通过api获取其父类及其实现接口的集合,并放入map中缓存,
// 第二次直接从map中取
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) {
// 默认情况下, 如果没有订阅者订阅该事件, 则打印如下信息,并且发送NoSubscriberEvent事件
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
继续简单的说下上述postSingleEvent
过程: 先判断是否支持事件继承,(默认情况下支持)如果支持,则寻找此事件对应类所有的父类,以及实现的接口,并发送。如果不支持,则仅发送此事件。 换句话说,如果支持事件继承, 订阅者订阅该事件的父类,或者其实现的接口,都能接受到该事件。写了个小demo
大家看看:child
继承parent
,并且实现了interfaceA
,interfaceB
。
public class Child extends Parent implements interfaceA, interfaceB {
}
// 发送child事件,则订阅了其父类或者其实现接口的订阅者,都能接受child事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void onInterfaceAEvent(interfaceA a) {
Log.i(TAG, "onInterfaceAEvent: " + a.toString());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onInterfaceBEvent(interfaceB b) {
Log.i(TAG, "onInterfaceBEvent: " + b.toString());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onParrentEvent(Parent p) {
Log.i(TAG, "onParrentEvent: " + p.toString());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onChildEvent(Child c) {
Log.i(TAG, "onChildEvent: " + c.toString());
}
postSingleEvent
中真正发送事件的方法是postSingleEventForEventType
,我们继续查看该方法干了什么勾当:
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
在指定的线程回调订阅方法:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
// 订阅者的订阅方法需要在哪个线程调用
switch (subscription.subscriberMethod.threadMode) {
// 在调用post的线程,则直接调用订阅方法
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
// 需要在主线程回调,并且调用post的线程也是主线程,则直接调用订阅方法
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
// 需要在主线程回调,调用post的线程不是主线程,则通过mainThreadPoster切换到主线程
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
// 需要在非主线程回调,调用post的线程也是主线程,则通过backgroundPoster切换到子线程
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
// 需要在非主线程回调,并且调用post的线程也是非主线程,则直接调用订阅方法
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
// 不论调用post的线程是否为主线程,都使用一个空闲线程来处理
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
至此,整个post
过程也就结束了。
至于postSticky
只是比post
多了一个步奏,在发布事件之前,先将该事件放入粘性事件集合stickyEvents
(事件类型作为key,具体事件作为value)中,当有订阅者订阅该事件并且注明接受粘性事件看,则能接收到最近的一个该事件。
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);
}
最后借用网络上的一幅图来总结整个post
流程: