轉(zhuǎn)載自:http://www.reibang.com/p/83e44261e095
注冊(cè)register
public void register(Object subscriber) {
// 首先會(huì)獲取注冊(cè)的對(duì)象的類型
Class<?> subscriberClass = subscriber.getClass();
// 然后獲取注冊(cè)的對(duì)象的訂閱方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
// 對(duì)當(dāng)前實(shí)例加鎖,并不斷執(zhí)行監(jiān)聽(tīng)的邏輯
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 對(duì)訂閱方法進(jìn)行注冊(cè)
subscribe(subscriber, subscriberMethod);
}
}
}
查找訂閱者的訂閱方法findSubscriberMethods
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
// 這里首先從緩存當(dāng)中嘗試去取該訂閱者的訂閱方法
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// 當(dāng)緩存中沒(méi)有找到該觀察者的訂閱方法的時(shí)候使用下面的兩種方法獲取方法信息
if (ignoreGeneratedIndex) {
//是否忽略注解器生成的MyEventBusIndex
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//放到緩存里
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
- 這里我們先從緩存當(dāng)中嘗試獲取某個(gè)觀察者中的所有訂閱方法,如果沒(méi)有可用緩存的話就從該類中查找訂閱方法哗魂,并在返回結(jié)果之前將這些方法信息放置到緩存當(dāng)中。這里的
ignoreGeneratedIndex
參數(shù)表示是否忽略注解器生成的MyEventBusIndex
组题,該值默認(rèn)為false崔列。
獲取訂閱方法findUsingInfo
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
// 這里通過(guò)FindState對(duì)象來(lái)存儲(chǔ)找到的方法信息
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
// 這里是一個(gè)循環(huán)操作峻呕,會(huì)從當(dāng)前類開(kāi)始遍歷該類的所有父類
while (findState.clazz != null) {
// 獲取訂閱者信息
findState.subscriberInfo = getSubscriberInfo(findState); //#1
// 如果使用了MyEventBusIndex,將會(huì)進(jìn)入到這里并獲取訂閱方法信息
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
// 未使用MyEventBusIndex將會(huì)進(jìn)入這里使用反射獲取方法信息
findUsingReflectionInSingleClass(findState); //#2
}
// 將findState.clazz設(shè)置為當(dāng)前的findState.clazz的父類
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
從當(dāng)前訂閱者類開(kāi)始直到它最頂層的父類進(jìn)行遍歷來(lái)獲取訂閱方法信息。這里在循環(huán)的內(nèi)部會(huì)根據(jù)我們是否使用了MyEventBusIndex
走兩條路線斤寇,對(duì)于我們沒(méi)有使用它的娘锁,會(huì)直接使用反射來(lái)獲取訂閱方法信息间雀,即進(jìn)入2
處
使用反射從訂閱者中得到訂閱方法findUsingReflectionInSingleClass
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 獲取該類中聲明的所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
// 對(duì)方法進(jìn)行遍歷判斷
for (Method method : methods) {
int modifiers = method.getModifiers();
// 這里會(huì)對(duì)方法的修飾符進(jìn)行校驗(yàn)
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class<?>[] parameterTypes = method.getParameterTypes();
// 判斷方法的參數(shù)量,只處理一個(gè)參數(shù)
if (parameterTypes.length == 1) {
// 獲取方法的注解连锯,用來(lái)從注解中獲取注解的聲明信息
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
// 獲取該方法的第一個(gè)參數(shù)
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 最終將封裝之后的方法塞入到列表中
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
- 對(duì)當(dāng)前類中聲明的所有方法進(jìn)行校驗(yàn)驳规,并將符合要求的方法的信息封裝成一個(gè)
SubscriberMethod
對(duì)象塞到列表中医男。
注冊(cè)訂閱事件subscribe
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
// 將所有的觀察者和訂閱方法封裝成一個(gè)Subscription對(duì)象 #1
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 嘗試從緩存中根據(jù)事件類型來(lái)獲取所有的Subscription對(duì)象
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
// 指定的事件類型沒(méi)有對(duì)應(yīng)的觀察對(duì)象的時(shí)候
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
// 這里會(huì)根據(jù)新加入的方法的優(yōu)先級(jí)決定插入到隊(duì)列中的位置
int size = subscriptions.size(); //#2
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// 這里又會(huì)從“訂閱者-事件類型”列表中嘗試獲取該訂閱者對(duì)應(yīng)的所有事件類型
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); //#3
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// 如果是黏性事件還要進(jìn)行如下的處理
if (subscriberMethod.sticky) { //#4
if (eventInheritance) {
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
// 這里會(huì)向該觀察者通知所有的黏性事件
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
這里涉及到了幾個(gè)集合镀梭,它們是用來(lái)做緩存的刀森,還有就是來(lái)維護(hù)觀察者报账、事件類型和訂閱方法之間的關(guān)系的。注冊(cè)觀察的方法比較長(zhǎng)透罢,我們可以一點(diǎn)一點(diǎn)來(lái)看羽圃。
首先斩郎,會(huì)在代碼1處將觀察者和訂閱方法封裝成一個(gè)Subscription對(duì)象。然后,在2處用到了CopyOnWriteArrayList這個(gè)集合炼幔,它是一種適用于多讀寫(xiě)少場(chǎng)景的數(shù)據(jù)結(jié)構(gòu)乃秀,是一種線程安全的數(shù)組型的數(shù)據(jù)結(jié)構(gòu),主要用來(lái)存儲(chǔ)一個(gè)事件類型所對(duì)應(yīng)的全部的Subscription對(duì)象圆兵。EventBus在這里通過(guò)一個(gè)Map<Class<?>, CopyOnWriteArrayList<Subscription>>類型的哈希表來(lái)維護(hù)這個(gè)映射關(guān)系跺讯。
然后,我們的程序執(zhí)行到2處超凳,在這里會(huì)對(duì)Subscription對(duì)象的列表進(jìn)行遍歷愈污,并根據(jù)訂閱方法的優(yōu)先級(jí),為當(dāng)前的Subscription對(duì)象尋找一個(gè)合適的位置轮傍。
3的地方主要的邏輯是獲取指定的觀察者對(duì)應(yīng)的全部的觀察事件類型暂雹,這里也是通過(guò)一個(gè)哈希表來(lái)維護(hù)這種映射關(guān)系的。
然后创夜,在代碼4處杭跪,程序會(huì)根據(jù)當(dāng)前的訂閱方法是否是黏性的,來(lái)決定是否將當(dāng)前緩存中的信息發(fā)送給新訂閱的方法驰吓。這里會(huì)通過(guò)checkPostStickyEventToSubscription方法來(lái)發(fā)送信息涧尿,它內(nèi)部的實(shí)現(xiàn)的邏輯和post方法類似。
取消注冊(cè)unregister
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
取消注冊(cè)的邏輯比較比較簡(jiǎn)單檬贰,基本上就是注冊(cè)操作反過(guò)來(lái)——將當(dāng)前訂閱方法的信息從緩存中踢出來(lái)姑廉,我們不再進(jìn)行分分析。下面我們分析另一個(gè)比較重要的地方偎蘸,即發(fā)送事件相關(guān)的邏輯
通知post
public void post(Object event) {
// 這里從線程局部變量中取出當(dāng)前線程的狀態(tài)信息
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
// 將當(dāng)前要發(fā)送的事件加入到隊(duì)列中
eventQueue.add(event);
if (!postingState.isPosting) {
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
// 不斷循環(huán)來(lái)發(fā)送事件
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState); // #1
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
- 這里的
currentPostingThreadState
是一個(gè)ThreadLocal
類型的變量庄蹋,其中存儲(chǔ)了對(duì)應(yīng)于當(dāng)前線程的PostingThreadState
對(duì)象瞬内,該對(duì)象中存儲(chǔ)了當(dāng)前線程對(duì)應(yīng)的事件列表和線程的狀態(tài)信息等。
從上面的代碼中可以看出限书,post
方法會(huì)在1處不斷從當(dāng)前線程對(duì)應(yīng)的隊(duì)列中取出事件并進(jìn)行發(fā)布虫蝶。下面我們看以下這里的postSingleEvent
方法。
postSingleEvent
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);
// 對(duì)上面的事件進(jìn)行處理
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
// 找不到該事件的異常處理
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
- 我們會(huì)根據(jù)
eventInheritance
的值決定是否要同時(shí)遍歷當(dāng)前事件的所有父類的事件信息并進(jìn)行分發(fā)倦西。如果設(shè)置為true就將執(zhí)行這一操作能真,并最終使用postSingleEventForEventType
對(duì)每個(gè)事件類型進(jìn)行處理
postSingleEventForEventType
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
// 獲取指定的事件對(duì)應(yīng)的所有的觀察對(duì)象
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
// 遍歷觀察對(duì)象,并最終執(zhí)行事件的分發(fā)操作
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;
}
- 通過(guò)傳入的事件類型到緩存中取尋找它對(duì)應(yīng)的全部的
Subscription
扰柠,然后對(duì)得到的Subscription
列表進(jìn)行遍歷粉铐,并依次調(diào)用postToSubscription
方法執(zhí)行事件的發(fā)布操作。
postToSubscription
下面是postToSubscription
方法的代碼卤档,這里我們會(huì)根據(jù)訂閱方法指定的threadMode信息來(lái)執(zhí)行不同的發(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 MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(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);
}
}
在上面的方法中蝙泼,會(huì)根據(jù)當(dāng)前的線程狀態(tài)和訂閱方法指定的threadMode信息來(lái)決定合適觸發(fā)方法。
這里的invokeSubscriber會(huì)在當(dāng)前線程中立即調(diào)用反射來(lái)觸發(fā)指定的觀察者的訂閱方法劝枣。否則會(huì)根據(jù)具體的情況將事件加入到不同的隊(duì)列中進(jìn)行處理汤踏。
這里的mainThreadPoster最終繼承自Handler,當(dāng)調(diào)用它的enqueue方法的時(shí)候舔腾,它會(huì)發(fā)送一個(gè)事件并在它自身的handleMessage方法中從隊(duì)列中取值并進(jìn)行處理溪胶,從而達(dá)到在主線程中分發(fā)事件的目的。
這里的backgroundPoster實(shí)現(xiàn)了Runnable接口稳诚,它會(huì)在調(diào)用enqueue方法的時(shí)候哗脖,拿到EventBus的ExecutorService實(shí)例,并使用它來(lái)執(zhí)行自己扳还。在它的run方法中會(huì)從隊(duì)列中不斷取值來(lái)進(jìn)行執(zhí)行才避。