在上篇文章中,我们从源码里了解了EventBus的注册机制。这篇文章我们接着上篇,把另一半——发布来了解一下。
我们一般可以通过eventBus.getDefault().post(event)
的方式来发布一个事件,然后订阅了这个类型事件的类就会接收到这个事件并进行相应的处理。那么,我们就从post(event)
下手,看看post的原理是什么样子的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public void post(Object event) { 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; } } }
|
可以看到在当前线程里有个线程局部变量PostingThreadState
,这个对象里记录了当前线程的事件队列,是否主线程以及事件的订阅者等信息。
1 2 3 4 5 6 7 8 9 10 11
| final static class PostingThreadState { final List<Object> eventQueue = new ArrayList<Object>(); boolean isPosting; boolean isMainThread; Subscription subscription; Object event; boolean canceled; }
|
新发布的事件会添加到事件队列中,然后从队列头部拿出一个事件调用postSingleEvent()
方法进行发布。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; 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) { Log.d(TAG, "No subscribers registered for event " + eventClass); } if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) { post(new NoSubscriberEvent(this, event)); } } }
private List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { synchronized (eventTypesCache) { List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<Class<?>>(); Class<?> clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); addInterfaces(eventTypes, clazz.getInterfaces()); clazz = clazz.getSuperclass(); } eventTypesCache.put(eventClass, eventTypes); } return eventTypes; } }
|
这里有一个eventTypesCache
的集合,该集合内以事件类型为key,以该事件类型的父类、接口以及自己为value存储了该类事件的所有父类和接口的Class类型。当post一个新事件的时候,首先根据该事件的类型查找之前有没有发送过同样的事件,如果没有则存起来,方便下次使用。最后调用postSingleEventForEventType()
方法把该类型的事件发布出去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 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; }
|
这里我们看到了上篇文章中出现的subscriptionsByEventType
,从上篇文章我们知道这个集合里根据事件类型存储了订阅某类事件的所有类。所以这里首先根据事件类型拿到所有的该类型事件的订阅者,然后遍历调用postToSubscription()
方法,该方法通过反射的方式调用订阅者内的对应onEvent**
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case PostThread: invokeSubscriber(subscription, event); break; case MainThread: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BackgroundThread: 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); } }
|
可以看到,这里根据订阅者的方法名判断的方法应该在哪个线程模式下执行,分了4个分支。注释中对这几种模式的订阅者方法回调方式已经做了说明。
不管是那种线程模式,最终都会调用invokeSubscriber(Subscription subscription, Object event)
方法。
1 2 3 4 5
| void invokeSubscriber(Subscription subscription, Object event) {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
}
|
显然,这里使用了反射的方法来回调订阅者中的事件处理方法。至此,一个订阅/发布以及处理的流程就完成了。
当然,我们这里没有分析EventBus的高级使用方法,包括事件的阻断、粘滞事件等等,有兴趣的朋友可以自己研究下。