整體結構
自己沒有怎么花時間畫圖,怕可能有遺漏的地方
所以,先參考一下別人的代碼分析
(之前的內容,應該沒有雷同的地方,參考別人的分析,也是自我提高的過程)
我們先看一下下面的圖:
(來自 Trinea的分析:
http://a.codekk.com/detail/Android/Trinea/EventBus%20%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90)
(這個圖,雖然沒有說明,但是我們通過例如 SubscriberMethodFinder的屬性 還有圖:)
應該可以判斷這個分析, 也就是
上圖是2.x的版本,3.0和它還是有區別的, 我們暫時使用而已
我們再貼一下對應2.4和3.0的類
類名上看,除了一個 我們分析過的 @interface Subscribe 注解類以外,其他類都是一致的
(當然,我們簡單看過SubscriberMethodFinder 類, 里面的實現 區別還是挺大的, 2.x的很好理解, 3.0的相對2.x,要復雜很多)
簡單說明
來自 Trinea的上圖,簡單結構說明
(只是結構,因為3.0 和 2.x 部分類的實現還是有很大區別的)
我們結構按上圖分析, 具體源碼,根據實際情況,再做了解
EventBus類簡單關聯
從上圖,我們可以知道,EventBus關聯的類
- SubscriberMethodFinder
- Value為 CopyOnWriteArrayList<Subscription> 的Map
- 這里 CopyOnWriteArrayList的List,是線程安全的
- 我們看一下 CopyOnWriteArrayList類里面 add等方法都是 synchronized 的,我們可以知道是線程安全的,適合并發調用的情況
- 對應的value的泛型是 Subcription,也就是說, 間接 關聯 Subcription類
- HandlerPoster
- BackgroundPoster
- AsyncPoster
- EventBusBuilder
其中
- SubscriberMethodFinder ,
- Subscription
- 每次register后,都會通過SubscriberMethodFinder 去查找SubscriberMethod,在拼接為Subscription
- 內部的SubscriberMethod引用在SubscriberMethodFinder 經常被使用
- Subscription只是在 SubscriberMethod 外面包了一層,可以判斷是否equal
- 這個類2.x 和 3.0 也有區別。2.x有對應的優先級 priority 屬性, 3.0沒有
- EventBusBuilder
- EventBusBuilder 里面的線程池相關的ExecutorService對象,我們沒有提過
- 其實,也只是創建的默認的Executors.newCachedThreadPool(),
- 具體也只是傳遞到EventBus中,最后被后面的XxxxPoster等類調用
我們都大體分析過,剩下的,只有 **XxxxPoster 等類 **了
XxxxPoster 在EventBus中的調用
我們先看一下,對應的屬性名稱:
- HandlerPoster mainThreadPoster
- BackgroundPoster backgroundPoster
- AsyncPoster asyncPoster
我們對應的代碼,無論是怎么調用,最終都會到
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);
}
}
我們前面分析注解的時候,知道
對應的ThreadMode通過@Subscribe注解傳入的,如果不傳,默認為ThreadMode.POSTING
上面大體有下面幾種方式
- invokeSubscriber(subscription, event);
- mainThreadPoster.enqueue(subscription, event);
- backgroundPoster.enqueue(subscription, event);
- asyncPoster.enqueue(subscription, event);
而invokeSubscriber方法,大體就是調用 Subscription 中 SubscriberMethod的Method反射,
從而調用對應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個xxxPoster
其他的3個xxxPoster的enqueue(subscription, event) 方法
就是調用封裝類對應的enqueue(subscription, event)方法
(個人感覺,這里都是調用相同的代碼,寫一個統一接口,可能會更方便一點)
這里
- BackgroundPoster 和 AsyncPoster 都是通過
eventBus.getExecutorService().execute(this) 將當然這個Runnable加入線程池執行。 - HandlerPoster 通過 Handler 去處理
無論怎么樣,最后,都會 EventBus的invokeSubscriber(pendingPost)去反射調用方法
這里我們通過 Trinea 的類圖,可以發現,
最終都是關聯 PendingPostQueue 實現的,
而 PendingPostQueue 是關聯 PendingPost 實現的
- PendingPostQueue類
- 只是一個簡單的雙向鏈表
- 有2個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的時候,wait對應時間后,調用poll
- PendingPost類
- 有一個static List<PendingPost> 容器對象,在內存的 靜態區 ,這樣可以保證對應的唯一性
- static 的 obtainPendingPost方法
- 這里通過判斷size,確定重新創建一個PendingPost對象,還是取出對象池中最后一個對象返回
- static 的 releasePendingPost 方法
- 在 EventBus中的 invokeSubscriber 方法, 在調用反射之前,會調用 PendingPost的releasePendingPost
- releasePendingPost 方法,會將對象中的屬性都設置為null,并且放入對象池中
- (個人覺得, 這樣也就節約了棧內存的消耗。既然只是為了節約棧內存的消耗,為什么要用雙向鏈表?自己就不太明白了)
大致流程
這里,雖然一些寫法,自己還不太清楚為什么
只是簡單理解和畫一下自己的理解
或者說, 可以更簡單的實現,
本來執行就是用線程池,為什么其他地方,還要寫這么麻煩
但是,大體還是很好理解的,圖中左邊,右邊都是注冊的Subscribe
(當然,細節還有很多地方不理解,大體畫了個圖,如果有問題的地方,歡迎大家拍磚,本人會第一時間做修改)
3種Poster提交
HandlerPoster提交
最后,再較大體的看一下調用過程
(因為比較簡單,自己就不畫了,借用 Trinea 大神 的圖)
還有
簡單總結
- 之所以用起來比較簡單, 是因為,調用端:注冊,接收 和 發消息 可以解耦
- 通過EventBusBuilder初始化一些變量 和 線程池
- register通過 SubscriberMethodFinder 類 由 類名 和 注解,按key為類名 和 value為線程安全的CopyOnWriteArrayList存儲
- 有的直接通過反射調用。有的通過 BackgroundPoster,AsyncPoster 或者 HandlerPoster 的方法,添加到 雙向鏈表 中,再依次反射調用(具體見前面的分析)
- 最后,添加注解@Subscribe的地方,被反射調用,實現通知