Eventbus3代碼分析(七):整體結(jié)構(gòu)


整體結(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的類

EventBus2.4
EventBus3.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é)

  1. 之所以用起來比較簡單, 是因?yàn)?,調(diào)用端:注冊,接收 和 發(fā)消息 可以解耦
  2. 通過EventBusBuilder初始化一些變量 和 線程池
  3. register通過 SubscriberMethodFinder 類 由 類名 和 注解,按key為類名 和 value為線程安全的CopyOnWriteArrayList存儲
  4. 有的直接通過反射調(diào)用。有的通過 BackgroundPoster,AsyncPoster 或者 HandlerPoster 的方法,添加到 雙向鏈表 中,再依次反射調(diào)用(具體見前面的分析)
  5. 最后,添加注解@Subscribe的地方,被反射調(diào)用,實(shí)現(xiàn)通知
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容