EventBus原始碼解析

鋸齒流沙發表於2017-12-26

之前介紹過EventBus的使用,如果不知道如何使用的,可以參考我的這篇文章《EventBus使用詳解》,個人覺得EventBus的用法簡單方便,是非常棒的事件匯流排。

接下來,帶大家好好的解析一下EventBus的原始碼,看下EventBus是如何實現訂閱/釋出事件的。本文主要從基本流程上解析。

資訊儲存.png

這是我分析過程中,對EventBus理解的主要資訊儲存類,以及他們之間的查詢流程。基本上他們是按照這個流程查詢到訂閱方法,然後通過反射進行釋出事件,在相應的訂閱方法進行事件的響應。

EventBus.getDefault()

getDefault方法:初始化EventBus,並且使用單例模式實現,主要做的事情就是初始化,包括:EventBusBuilder、對映池等。

getDefault.png

getDefault.png

EventBus.png

以上的截圖基本上我已經做了註釋,DEFAULT_BUILDER就是new了一個EventBusBuilder物件,EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();基本上EventBus所需要的資訊都已經初始化好的了。

register

EventBus的註冊方法

EventBus.png

首先通過subscriberMethodFinder.findSubscriberMethods獲取註冊類的所有註冊方法

findSubscriberMethods方法:

EventBus.png

這裡首先查詢方法快取池中有沒有該註冊類的訂閱方法,如果有就直接返回,如果沒有就通過findUsingInfo(subscriberClass)方法找出該註冊類的訂閱方法,查詢到該訂閱方法之後就會將方法快取到方法快取池中。

findUsingInfo方法:

EventBus.png

EventBus.png

EventBus.png

首先獲取FindState物件,並且將subscriberClass訂閱傳入initForSubscriber方法,初始化findState。而clazz就是我們傳入的subscriberClass,通過getSubscriberInfo獲取訂閱資訊為null

EventBus.png

繼續分析findUsingInfo方法,應為findState.subscriberInfonull,所有通過findUsingReflectionInSingleClass(findState)方法獲取訂閱資訊和訂閱方法。然後通過getMethodsAndRelease(findState)返回該訂閱類的所有訂閱方法。

findUsingReflectionInSingleClass(findState)方法

最後通過findUsingReflectionInSingleClass(findState)獲取訂閱類的所有訂閱方法,因此我們重點看下這個方法的實現。

EventBus.png
EventBus.png

首先通過getDeclaredMethods()獲取該訂閱類的自身宣告的所有方法,然後通過遍歷查詢:修飾符為:public,不是staticabstract型別的方法,並且同時:方法引數只有一個,且註解型別為Subscribe的方法。最後將方法method、事件型別eventType、執行緒模式threadMode等資訊存入一個名為SubscriberMethod的資訊類儲存。並且將該資訊類加入到findState.subscriberMethods方法集合。這裡的eventType就是使用方法的引數作為事件型別:在釋出事件中作用非常之大。

我們繼續看回findUsingInfo方法,最後兩個步驟呼叫moveToSuperclass()方法和getMethodsAndRelease(findState)方法

moveToSuperclass():

EventBus.png

getMethodsAndRelease(findState)

EventBus.png

主要做的事情就是釋放findState並且返回subscriberMethods訂閱方法的集合。

findState.recycle()

EventBus.png

以上就是根據訂閱類查詢訂閱方法的過程。有不明白的地方,可以看註釋。

繼續看回register註冊方法。

EventBus.png

獲取得到訂閱類的訂閱方法之後,就會遍歷訂閱方法集合,逐一進行訂閱。接下來看subscribe訂閱方法。

subscribe訂閱方法

EventBus.png
EventBus.png
EventBus.png

以上的截圖就是subscribe訂閱方法。主要做的事情只有三件:1)、將事件型別(eventType)和訂閱資訊集合(CopyOnWriteArrayList)加入到訂閱型別和訂閱資訊集合的對映池(subscriptionsByEventType); 2)、將訂閱類(subscriber)訂閱型別集合(List<Class<?>> subscribedEvents)加入到訂閱型別集合和訂閱類的對映池; 3)、粘性事件加入到粘性事件集合。粘性事件會優先獲取釋出checkPostStickyEventToSubscription

以上就是訂閱的整個過程了。

unregister登出過程

EventBus.png

1、根據訂閱類得到訂閱型別集合

2、將訂閱型別集合遍歷,呼叫unsubscribeByEventType登出。

EventBus.png

1、根據訂閱型別獲取訂閱資訊的集合

2、將訂閱資訊集合進行遍歷,完成登出。

post 釋出過程

EventBus.png

這裡主要看postSingleEvent(eventQueue.remove(0), postingState)分發訊息的方法,而currentPostingThreadState就是ThreadLocal,關於ThreadLocal的作用,大家可以另查資料。 接下來我們檢視分發訊息的流程。

postSingleEvent:

EventBus.png

1)、lookupAllEventTypes(eventClass)根據事件類獲取所有的事件型別。

2)、呼叫postSingleEventForEventType(event, postingState, clazz)方法進行事件分發。

postSingleEventForEventType

EventBus.png

1)、subscriptionsByEventType.get(eventClass)根據事件型別從訂閱型別和訂閱資訊集合的對映池取出訂閱資訊集合。

2)、遍地訂閱資訊集合,呼叫postToSubscription方法對訂閱資訊進行分發。

postToSubscription

EventBus.png

這裡主要是根據不同的執行緒模式進行分發事件,預設的模式是POSTING,然後呼叫invokeSubscriber方法分發。

invokeSubscriber

EventBus.png

1)、這是分發的最終呼叫的方法,拿到了訂閱資訊類subscription,訂閱資訊裡面存放著subscriberMethod訂閱方法。

2)、subscription.subscriberMethod.method.invoke(subscription.subscriber, event);使用反射進行事件分發。

至此,已經完成了這個訂閱/釋出的流程。雖然其內部的實現過程複雜,但是我們使用EventBus事件匯流排卻簡單了,大大提高了我們的開發效率。

相關文章