距離上篇整整兩個月了,忙不是借口,反省。
上一篇文章介紹了register的過程,這篇接著來,一起看看EventBus發(fā)送事件的過程。EventBus可以通過post發(fā)送普通事件,還可以通過postSticky發(fā)送粘性事件。粘性事件與普通事件的區(qū)別在于:當(dāng)粘性事件發(fā)布后,若有訂閱者訂閱該事件,該訂閱者依然能收到最近一個該事件, 這點(diǎn)在上篇最后有提到。有了這個最基本的認(rèn)識,我們來看看這兩個方法的具體實(shí)現(xiàn)。
先瞅瞅發(fā)送普通事件post方法的源碼
public void post(Object event) {
// 獲取當(dāng)前線程的PostingThreadState
PostingThreadState postingState = currentPostingThreadState.get();
// 事件隊列
List<Object> eventQueue = postingState.eventQueue;
// 添加到事件隊列中
eventQueue.add(event);
// 如果沒有發(fā)送事件,則將事件隊列中的事件一一發(fā)送出去
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的流程:先獲取當(dāng)前調(diào)用post方法的PostingThreadState,并將該事件添加到事件隊列中,如果當(dāng)前沒有發(fā)送事件, 則通過postSingleEvent方法將隊列中的事件一一發(fā)送出去。
繼續(xù)分析postSingleEvent方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
// 獲取該事件的class
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// 是否支持事件繼承(默認(rèn)是支持的)
if (eventInheritance) {
// 查找所有跟eventClass相關(guān)的類(包括eventClass實(shí)現(xiàn)的接口以及父類)
// 若是第一次發(fā)送eventClass,通過api獲取其父類及其實(shí)現(xiàn)接口的集合,并放入map中緩存,
// 第二次直接從map中取
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
// 發(fā)送事件
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
// 發(fā)送事件
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
// 默認(rèn)情況下, 如果沒有訂閱者訂閱該事件, 則打印如下信息,并且發(fā)送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));
}
}
}
繼續(xù)簡單的說下上述postSingleEvent過程: 先判斷是否支持事件繼承,(默認(rèn)情況下支持)如果支持,則尋找此事件對應(yīng)類所有的父類,以及實(shí)現(xiàn)的接口,并發(fā)送。如果不支持,則僅發(fā)送此事件。 換句話說,如果支持事件繼承, 訂閱者訂閱該事件的父類,或者其實(shí)現(xiàn)的接口,都能接受到該事件。寫了個小demo大家看看:child 繼承parent,并且實(shí)現(xiàn)了interfaceA,interfaceB。
public class Child extends Parent implements interfaceA, interfaceB {
}
// 發(fā)送child事件,則訂閱了其父類或者其實(shí)現(xiàn)接口的訂閱者,都能接受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中真正發(fā)送事件的方法是postSingleEventForEventType,我們繼續(xù)查看該方法干了什么勾當(dāng):
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在指定的線程回調(diào)訂閱方法:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
// 訂閱者的訂閱方法需要在哪個線程調(diào)用
switch (subscription.subscriberMethod.threadMode) {
// 在調(diào)用post的線程,則直接調(diào)用訂閱方法
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
// 需要在主線程回調(diào),并且調(diào)用post的線程也是主線程,則直接調(diào)用訂閱方法
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
// 需要在主線程回調(diào),調(diào)用post的線程不是主線程,則通過mainThreadPoster切換到主線程
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
// 需要在非主線程回調(diào),調(diào)用post的線程也是主線程,則通過backgroundPoster切換到子線程
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
// 需要在非主線程回調(diào),并且調(diào)用post的線程也是非主線程,則直接調(diào)用訂閱方法
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
// 不論調(diào)用post的線程是否為主線程,都使用一個空閑線程來處理
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
至此,整個post過程也就結(jié)束了。
至于postSticky只是比post多了一個步奏,在發(fā)布事件之前,先將該事件放入粘性事件集合stickyEvents(事件類型作為key,具體事件作為value)中,當(dāng)有訂閱者訂閱該事件并且注明接受粘性事件看,則能接收到最近的一個該事件。
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);
}
最后借用網(wǎng)絡(luò)上的一幅圖來總結(jié)整個post流程:
