整體結(jié)構(gòu)
自己沒有怎么花時(shí)間畫圖,怕可能有遺漏的地方
所以,先參考一下別人的代碼分析
(之前的內(nèi)容,應(yīng)該沒有雷同的地方,參考別人的分析,也是自我提高的過程)
我們先看一下下面的圖:
(來自 Trinea的分析:
http://a.codekk.com/detail/Android/Trinea/EventBus%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90)

(這個(gè)圖,雖然沒有說明,但是我們通過例如 SubscriberMethodFinder的屬性 還有圖:)

應(yīng)該可以判斷這個(gè)分析, 也就是
上圖是2.x的版本,3.0和它還是有區(qū)別的, 我們暫時(shí)使用而已
我們再貼一下對應(yīng)2.4和3.0的類


類名上看,除了一個(gè) 我們分析過的 @interface Subscribe 注解類以外,其他類都是一致的
(當(dāng)然,我們簡單看過SubscriberMethodFinder 類, 里面的實(shí)現(xiàn) 區(qū)別還是挺大的, 2.x的很好理解, 3.0的相對2.x,要復(fù)雜很多)
簡單說明
來自 Trinea的上圖,簡單結(jié)構(gòu)說明
(只是結(jié)構(gòu),因?yàn)?.0 和 2.x 部分類的實(shí)現(xiàn)還是有很大區(qū)別的)
我們結(jié)構(gòu)按上圖分析, 具體源碼,根據(jù)實(shí)際情況,再做了解
EventBus類簡單關(guān)聯(lián)
從上圖,我們可以知道,EventBus關(guān)聯(lián)的類
- SubscriberMethodFinder
- Value為 CopyOnWriteArrayList<Subscription> 的Map
- 這里 CopyOnWriteArrayList的List,是線程安全的
- 我們看一下 CopyOnWriteArrayList類里面 add等方法都是 synchronized 的,我們可以知道是線程安全的,適合并發(fā)調(diào)用的情況
- 對應(yīng)的value的泛型是 Subcription,也就是說, 間接 關(guān)聯(lián) Subcription類
- HandlerPoster
- BackgroundPoster
- AsyncPoster
- EventBusBuilder
其中
- SubscriberMethodFinder ,
- Subscription
- 每次register后,都會通過SubscriberMethodFinder 去查找SubscriberMethod,在拼接為Subscription
- 內(nèi)部的SubscriberMethod引用在SubscriberMethodFinder 經(jīng)常被使用
- Subscription只是在 SubscriberMethod 外面包了一層,可以判斷是否equal
- 這個(gè)類2.x 和 3.0 也有區(qū)別。2.x有對應(yīng)的優(yōu)先級 priority 屬性, 3.0沒有
- EventBusBuilder
- EventBusBuilder 里面的線程池相關(guān)的ExecutorService對象,我們沒有提過
- 其實(shí),也只是創(chuàng)建的默認(rèn)的Executors.newCachedThreadPool(),
- 具體也只是傳遞到EventBus中,最后被后面的XxxxPoster等類調(diào)用
我們都大體分析過,剩下的,只有 **XxxxPoster 等類 **了
XxxxPoster 在EventBus中的調(diào)用
我們先看一下,對應(yīng)的屬性名稱:
- HandlerPoster mainThreadPoster
- BackgroundPoster backgroundPoster
- AsyncPoster asyncPoster
我們對應(yīng)的代碼,無論是怎么調(diào)用,最終都會到
postToSubscription方法
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);
}
}
我們前面分析注解的時(shí)候,知道
對應(yīng)的ThreadMode通過@Subscribe注解傳入的,如果不傳,默認(rèn)為ThreadMode.POSTING
上面大體有下面幾種方式
- invokeSubscriber(subscription, event);
- mainThreadPoster.enqueue(subscription, event);
- backgroundPoster.enqueue(subscription, event);
- asyncPoster.enqueue(subscription, event);
而invokeSubscriber方法,大體就是調(diào)用 Subscription 中 SubscriberMethod的Method反射,
從而調(diào)用對應(yīng)register類中的方法
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
其他的3個(gè)xxxPoster
其他的3個(gè)xxxPoster的enqueue(subscription, event) 方法
就是調(diào)用封裝類對應(yīng)的enqueue(subscription, event)方法
(個(gè)人感覺,這里都是調(diào)用相同的代碼,寫一個(gè)統(tǒng)一接口,可能會更方便一點(diǎn))
這里
- BackgroundPoster 和 AsyncPoster 都是通過
eventBus.getExecutorService().execute(this) 將當(dāng)然這個(gè)Runnable加入線程池執(zhí)行。 - HandlerPoster 通過 Handler 去處理
無論怎么樣,最后,都會 EventBus的invokeSubscriber(pendingPost)去反射調(diào)用方法
這里我們通過 Trinea 的類圖,可以發(fā)現(xiàn),
最終都是關(guān)聯(lián) PendingPostQueue 實(shí)現(xiàn)的,
而 PendingPostQueue 是關(guān)聯(lián) PendingPost 實(shí)現(xiàn)的
- PendingPostQueue類
- 只是一個(gè)簡單的雙向鏈表
- 有2個(gè)PendingPost對象屬性,head 和 tail,
- enqueue方法,可以把對象對象賦值給類中的head 和 tail,還有head.next 和 tail.next
- (如果tail == null, head != null, 會拋異常)
- poll()方法, 釋放對象。賦值 pendingPost 為 head 后,操作 head 和 tail,返回 pendingPost
- poll(int maxMillisToWait)方法,head為null的時(shí)候,wait對應(yīng)時(shí)間后,調(diào)用poll
- PendingPost類
- 有一個(gè)static List<PendingPost> 容器對象,在內(nèi)存的 靜態(tài)區(qū) ,這樣可以保證對應(yīng)的唯一性
- static 的 obtainPendingPost方法
- 這里通過判斷size,確定重新創(chuàng)建一個(gè)PendingPost對象,還是取出對象池中最后一個(gè)對象返回
- static 的 releasePendingPost 方法
- 在 EventBus中的 invokeSubscriber 方法, 在調(diào)用反射之前,會調(diào)用 PendingPost的releasePendingPost
- releasePendingPost 方法,會將對象中的屬性都設(shè)置為null,并且放入對象池中
- (個(gè)人覺得, 這樣也就節(jié)約了棧內(nèi)存的消耗。既然只是為了節(jié)約棧內(nèi)存的消耗,為什么要用雙向鏈表?自己就不太明白了)
大致流程
這里,雖然一些寫法,自己還不太清楚為什么
只是簡單理解和畫一下自己的理解
或者說, 可以更簡單的實(shí)現(xiàn),
本來執(zhí)行就是用線程池,為什么其他地方,還要寫這么麻煩
但是,大體還是很好理解的,圖中左邊,右邊都是注冊的Subscribe
(當(dāng)然,細(xì)節(jié)還有很多地方不理解,大體畫了個(gè)圖,如果有問題的地方,歡迎大家拍磚,本人會第一時(shí)間做修改)
3種Poster提交

HandlerPoster提交

最后,再較大體的看一下調(diào)用過程
(因?yàn)楸容^簡單,自己就不畫了,借用 Trinea 大神 的圖)

還有

簡單總結(jié)
- 之所以用起來比較簡單, 是因?yàn)?,調(diào)用端:注冊,接收 和 發(fā)消息 可以解耦
- 通過EventBusBuilder初始化一些變量 和 線程池
- register通過 SubscriberMethodFinder 類 由 類名 和 注解,按key為類名 和 value為線程安全的CopyOnWriteArrayList存儲
- 有的直接通過反射調(diào)用。有的通過 BackgroundPoster,AsyncPoster 或者 HandlerPoster 的方法,添加到 雙向鏈表 中,再依次反射調(diào)用(具體見前面的分析)
- 最后,添加注解@Subscribe的地方,被反射調(diào)用,實(shí)現(xiàn)通知