之前介紹過EventBus
的使用,如果不知道如何使用的,可以參考我的這篇文章《EventBus使用詳解》,個人覺得EventBus
的用法簡單方便,是非常棒的事件匯流排。
接下來,帶大家好好的解析一下EventBus
的原始碼,看下EventBus是如何實現訂閱/釋出事件
的。本文主要從基本流程上解析。
這是我分析過程中,對EventBus理解的主要資訊儲存類,以及他們之間的查詢流程。基本上他們是按照這個流程查詢到訂閱方法,然後通過反射進行釋出事件,在相應的訂閱方法進行事件的響應。
EventBus.getDefault()
getDefault
方法:初始化EventBus
,並且使用單例模式實現,主要做的事情就是初始化,包括:EventBusBuilder、對映池等。
以上的截圖基本上我已經做了註釋,DEFAULT_BUILDER
就是new了一個EventBusBuilder
物件,EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
基本上EventBus
所需要的資訊都已經初始化好的了。
register
EventBus的註冊方法
首先通過subscriberMethodFinder.findSubscriberMethods
獲取註冊類的所有註冊方法
findSubscriberMethods方法:
這裡首先查詢方法快取池
中有沒有該註冊類的訂閱方法,如果有就直接返回,如果沒有就通過findUsingInfo(subscriberClass)
方法找出該註冊類的訂閱方法,查詢到該訂閱方法之後就會將方法快取到方法快取池
中。
findUsingInfo方法:
首先獲取FindState物件,並且將subscriberClass
訂閱傳入initForSubscriber
方法,初始化findState。而clazz
就是我們傳入的subscriberClass
,通過getSubscriberInfo
獲取訂閱資訊為null
繼續分析findUsingInfo
方法,應為findState.subscriberInfo
為null
,所有通過findUsingReflectionInSingleClass(findState)
方法獲取訂閱資訊和訂閱方法。然後通過getMethodsAndRelease(findState)
返回該訂閱類的所有訂閱方法。
findUsingReflectionInSingleClass(findState)方法
最後通過findUsingReflectionInSingleClass(findState)
獲取訂閱類的所有訂閱方法,因此我們重點看下這個方法的實現。
首先通過getDeclaredMethods()
獲取該訂閱類的自身宣告的所有方法,然後通過遍歷查詢:修飾符為:public
,不是static
和abstract
型別的方法,並且同時:方法引數只有一個,且註解型別為Subscribe
的方法。最後將方法method
、事件型別eventType
、執行緒模式threadMode
等資訊存入一個名為SubscriberMethod
的資訊類儲存。並且將該資訊類加入到findState.subscriberMethods
方法集合。這裡的eventType
就是使用方法的引數作為事件型別:在釋出事件中作用非常之大。
我們繼續看回findUsingInfo
方法,最後兩個步驟呼叫moveToSuperclass()
方法和getMethodsAndRelease(findState)
方法
moveToSuperclass():
getMethodsAndRelease(findState)
:
主要做的事情就是釋放findState
並且返回subscriberMethods
訂閱方法的集合。
findState.recycle()
:
以上就是根據訂閱類查詢訂閱方法的過程。有不明白的地方,可以看註釋。
繼續看回register
註冊方法。
獲取得到訂閱類的訂閱方法之後,就會遍歷訂閱方法集合,逐一進行訂閱。接下來看subscribe
訂閱方法。
subscribe
訂閱方法
以上的截圖就是subscribe
訂閱方法。主要做的事情只有三件:1)、將事件型別(eventType)和訂閱資訊集合(CopyOnWriteArrayList)加入到訂閱型別和訂閱資訊集合的對映池(subscriptionsByEventType)
;
2)、將訂閱類(subscriber)
和訂閱型別集合(List<Class<?>> subscribedEvents)
加入到訂閱型別集合和訂閱類的對映池
;
3)、粘性事件加入到粘性事件集合。粘性事件會優先獲取釋出checkPostStickyEventToSubscription
。
以上就是訂閱的整個過程了。
unregister登出過程
1、根據訂閱類
得到訂閱型別集合
2、將訂閱型別集合
遍歷,呼叫unsubscribeByEventType
登出。
1、根據訂閱型別
獲取訂閱資訊的集合
2、將訂閱資訊集合
進行遍歷,完成登出。
post 釋出過程
這裡主要看postSingleEvent(eventQueue.remove(0), postingState)
分發訊息的方法,而currentPostingThreadState
就是ThreadLocal
,關於ThreadLocal
的作用,大家可以另查資料。
接下來我們檢視分發訊息的流程。
postSingleEvent:
1)、lookupAllEventTypes(eventClass)
根據事件類獲取所有的事件型別。
2)、呼叫postSingleEventForEventType(event, postingState, clazz)
方法進行事件分發。
postSingleEventForEventType
:
1)、subscriptionsByEventType.get(eventClass)
根據事件型別從訂閱型別和訂閱資訊集合的對映池
取出訂閱資訊集合。
2)、遍地訂閱資訊集合
,呼叫postToSubscription
方法對訂閱資訊進行分發。
postToSubscription
:
這裡主要是根據不同的執行緒模式
進行分發事件,預設的模式是POSTING,然後呼叫invokeSubscriber
方法分發。
invokeSubscriber
:
1)、這是分發的最終呼叫的方法,拿到了訂閱資訊類subscription
,訂閱資訊裡面存放著subscriberMethod
訂閱方法。
2)、subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
使用反射進行事件分發。
至此,已經完成了這個訂閱/釋出
的流程。雖然其內部的實現過程複雜,但是我們使用EventBus
事件匯流排卻簡單了,大大提高了我們的開發效率。