Eventbus3代碼分析(七):整體結構


整體結構

自己沒有怎么花時間畫圖,怕可能有遺漏的地方
所以,先參考一下別人的代碼分析
(之前的內容,應該沒有雷同的地方,參考別人的分析,也是自我提高的過程)
我們先看一下下面的圖:
(來自 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的類

EventBus2.4
EventBus3.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 大神 的圖)


還有



簡單總結

  1. 之所以用起來比較簡單, 是因為,調用端:注冊,接收 和 發消息 可以解耦
  2. 通過EventBusBuilder初始化一些變量 和 線程池
  3. register通過 SubscriberMethodFinder 類 由 類名 和 注解,按key為類名 和 value為線程安全的CopyOnWriteArrayList存儲
  4. 有的直接通過反射調用。有的通過 BackgroundPoster,AsyncPoster 或者 HandlerPoster 的方法,添加到 雙向鏈表 中,再依次反射調用(具體見前面的分析)
  5. 最后,添加注解@Subscribe的地方,被反射調用,實現通知
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 項目到了一定階段會出現一種甜蜜的負擔:業務的不斷發展與人員的流動性越來越大,代碼維護與測試回歸流程越來越繁瑣。這個...
    fdacc6a1e764閱讀 3,209評論 0 6
  • 原文鏈接:http://blog.csdn.net/u012810020/article/details/7005...
    tinyjoy閱讀 563評論 1 5
  • 先吐槽一下博客園的MarkDown編輯器,推出的時候還很高興博客園支持MarkDown了,試用了下發現支持不完善就...
    Ten_Minutes閱讀 573評論 0 2
  • title: EventBus 源碼分析date: 2017-09-15 09:38:14tags: [Sourc...
    Passon_Fang閱讀 232評論 0 0
  • EventBus源碼閱讀記錄 EventBus是一個Android上用的消息分發的類庫,非常靈活好用,主要的原理是...
    圣騎士wind閱讀 703評論 0 6