在上一篇讲注册的时候讲到,会把一个EventType和与他相关的订阅方法放到subscriptionsEventType这个map里,所以先找出与这个event相关的父类和接口:
postingState是线程安全的,ThreadLocal类的,每次只分发一个event,标志器是isPosting,如果在分发过程中有新的事件需要分发,就加入到事件队列里,等上个事件执行完后,再执行,并且分发完所有的事件衙就重置isPosting。
/** Posts the given event to the event bus. */
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;
}
}
}
接下来看如何分发一个event:首先是看是否需要事件继承,默认是需要。如果需要的话,就需要找出这个事件类型的父类和相关接口,再分发,如果不需要,就直接分发。如果在分发的过程中没有找到相关的订阅者,就重新分发一个NoSubScriberEvent.
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))
;
}
}
}
找出这个事件类型的父类和接口:
/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
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
;
}
}
接下来就是分发流程:在分发的过程中,注意要根据当前线程是否是主线程来执行,如果是主线程,就交给Handler,否则交给eventBus的线程池执行,最后都通过invodeSubscriber方法来反射扫行订阅者。
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;
}
private void
postToSubscription
(Subscription subscription
,
Object event
, boolean
isMainThread) {
//
根据事件的执行线程类型,来找到相应的线程池,如果是主线程执行,而且本身就是主线程就交给当前进程,否则交给
handler
分发消息。
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
)
;
}
}