前言
接上篇EventBus源碼解析(一)EventBus事件訂閱,一直想著怎么寫出通俗易通的文章衡奥,無奈水平有限,想配圖卻不知從哪開始失息。如果文章哪里寫的不好或錯了,希望大神能指出并糾正盹兢。
正題
EventBus消息發(fā)送分為兩種绎秒,一種是普通發(fā)送,一種粘性發(fā)送剂娄。本篇文章講普通發(fā)送阅懦。
使用post就能完成一次普通的消息發(fā)送耳胎,參數(shù)為model類的實例惕它,發(fā)送之后訂閱者就會收到小心并處理事件。
下面看一下post的源碼:
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
/** 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);
//判斷消息是否已發(fā)送
if (!postingState.isPosting) {
//是否為主線程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
//標(biāo)記為已發(fā)送
postingState.isPosting = true;
//
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
//發(fā)送消息并移除已發(fā)送的消息
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
在post方法中钳宪,使用的是ThreadLocal解決多線程并發(fā)問題。至于它和synchronized鎖的區(qū)別搔体,感興趣的同學(xué)可以去了解一下半醉。這里給個地址徹底理解ThreadLocal。之后再把消息加入到隊列當(dāng)中呆奕,經(jīng)過判斷消息的各種狀態(tài)之后發(fā)送消息梁钾。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//eventInheritance默認(rèn)為true 在EventBusBuilder類中可設(shè)置
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 static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
synchronized (eventTypesCache) {
//從緩存中查找model類集合
List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class<?> clazz = eventClass;
//將model類的父類和接口添加至model類集合
while (clazz != null) {
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
//添加至緩存
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
/** Recurses through super interfaces. */
static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
for (Class<?> interfaceClass : interfaces) {
if (!eventTypes.contains(interfaceClass)) {
eventTypes.add(interfaceClass);
addInterfaces(eventTypes, interfaceClass.getInterfaces());
}
}
}
這段代碼檢查model類及其父類和接口,在添加接口和父類的while循環(huán)中,如果找不到父類后就會返回null則跳出循環(huán)四苇。每循環(huán)一次clazz都是不同的類月腋,添加接口時使用遞歸瓣赂,設(shè)計的非常巧妙。之后的工作就是把小心發(fā)送出去了
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//從subscriptionsByEventType中取出訂閱請求
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;
}
//根據(jù)訂閱請求中的線程信息發(fā)送消息
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BACKGROUND:
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);
}
}
發(fā)送請求的代碼非常簡單,在 subscribe(subscriber, subscriberMethod)(見第一篇)中subscriptionsByEventType已經(jīng)添加了訂閱信息牙勘,eventClass和eventType都是model類,所以取出的就是訂閱的消息請求集合了放钦。之后再遍歷訂閱集合恭金,根據(jù)訂閱信息中的線程參數(shù)去發(fā)送信息。然后通過反射完成消息的發(fā)送颓屑。