Android 淺析 EventBus (二) 原理
前言
Linus Benedict Torvalds : RTFSC – Read The Fucking Source Code
概括
本次分析從兩個(gè)方向深入,一個(gè)是從注冊(cè)開始,一個(gè)是從發(fā)送消息開始。從這兩個(gè)方向就能大致了解eventbus的運(yùn)作原理。
注冊(cè)原理

MainActivity
EventBus.getDefault().register(this);
EventBus的注冊(cè)就從這里開始。
Step 1.EventBus.getDefault()
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
這是一句很典型的單例寫法,整個(gè)eventbus在項(xiàng)目中是以單例的形式出現(xiàn)的。在初始化這塊調(diào)用的是EventBusBuilder的默認(rèn)參數(shù)。這也是Builder模式比較常用的。
Step 2.EventBus.register(Object subscriber)
這里是注冊(cè)訂閱者的地方,同樣的注冊(cè)方式有這么幾個(gè):
- register(Object subscriber)
- register(Object subscriber, int priority)
- registerSticky(Object subscriber)
- registerSticky(Object subscriber, int priority)
它們之間最主要的區(qū)別就是參數(shù)的不同。在實(shí)現(xiàn)上它們都是調(diào)用void register(Object subscriber, boolean sticky, int priority)函數(shù)實(shí)現(xiàn)的。
private synchronized void register(Object subscriber, boolean sticky, int priority) {
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
這里首先調(diào)用findSubscriberMethods()方法根據(jù)當(dāng)前訂閱者的類名查找到該類的所有訂閱者函數(shù)。
在獲取完所有訂閱者函數(shù)后調(diào)用subscribe方法。
Step 3.EventBus.subscribe(subscriber, subscriberMethod, ...)
這里是注冊(cè)函數(shù)的核心,分成三個(gè)部分:
- 通過(guò)
subscriptionsByEventType得到這個(gè)Event類型所有訂閱者信息隊(duì)列,然后根據(jù)優(yōu)先級(jí)將當(dāng)前訂閱者信息插入到隊(duì)列里面。 - 在
typesBySubscriber中得到當(dāng)前訂閱者訂閱的所有事件隊(duì)列,將此事件保存到隊(duì)列中,用于后續(xù)取消訂閱。 - 檢查這個(gè)事件是否是 Sticky 事件,如果是則從stickyEvents事件保存隊(duì)列中取出該事件類型最后一個(gè)事件發(fā)送給當(dāng)前訂閱者。
Step 4.EventBus.unregister(Object subscriber)
最后就是反注冊(cè),這里就比較簡(jiǎn)單了。
首先從typesBySubscriber獲取當(dāng)前訂閱者,然后找到此訂閱者的所有類型,將此訂閱者的所有類型從subscriptionsByEventType表里刪除。接著再把此訂閱者從typesBySubscriber中刪除。
發(fā)送原理

MainActivity
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
public void onEventMainThread(MessageEvent event) {
}
EventBus.getDefault().post(new MessageEvent("hello eventbus"));
EventBus.getDefault().post(this);
EventBus的注冊(cè)就從這里開始。其實(shí)這個(gè)就是一個(gè)序列化和反序列化的過(guò)程。將一段event打包然后再接受函數(shù)解包。
EventBus.post(Object event)
這個(gè)函數(shù)將收到的event發(fā)送到event bus。
首先將此事件保存到currentPostingThreadState的事件隊(duì)列里。
然后查看當(dāng)前是否有事件在發(fā)送,然后調(diào)用postSingleEvent()函數(shù)發(fā)送。
EventBus.postSingleEvent()
首先調(diào)用lookupAllEventTypes()獲取所有事件的類型,然后循環(huán)調(diào)用postSingleEventForEventType()函數(shù)發(fā)送事件。
EventBus.lookupAllEventTypes(...)
這里從當(dāng)前事件中獲取父類和接口,一直往上循環(huán)獲取直到最后。然后保存到eventTypesCache變量里。
EventBus.postSingleEventForEventType(...)
這里就是獲取每個(gè)事件,然后通過(guò)循環(huán)發(fā)送這些事件,會(huì)將事件的參數(shù)添加到PostingThreadState結(jié)構(gòu)體里傳到postToSubscription()函數(shù)來(lái)發(fā)送,這里就能區(qū)分是主界面線程還是非界面線程。最后再把參數(shù)都反初始化。
EventBus.postToSubscription(Subscription subscription, ...)
這個(gè)函數(shù)就是主要的分發(fā)函數(shù),根據(jù)每個(gè)事件的threadMode來(lái)分發(fā)到各自相應(yīng)的回調(diào)函數(shù)。
switch (subscription.subscriberMethod.threadMode) {
case PostThread:
case MainThread:
case BackgroundThread:
case Async:
}
這里主要就是分發(fā)到四個(gè)不同函數(shù)。
- invokeSubscriber()
- mainThreadPoster.enqueue()
- backgroundPoster.enqueue()
- asyncPoster.enqueue()
這里我們分別看下:
- PostThread:默認(rèn)的 ThreadMode,表示在執(zhí)行 Post 操作的線程直接調(diào)用訂閱者的事件響應(yīng)方法,不論該線程是否為主線程(UI 線程)。當(dāng)該線程為主線程時(shí),響應(yīng)方法中不能有耗時(shí)操作,否則有卡主線程的風(fēng)險(xiǎn)。適用場(chǎng)景:對(duì)于是否在主線程執(zhí)行無(wú)要求,但若Post線程為主線程,不能耗時(shí)的操作;
- MainThread:在主線程中執(zhí)行響應(yīng)方法。如果發(fā)布線程就是主線程,則直接調(diào)用訂閱者的事件響應(yīng)方法,否則通過(guò)主線程的 Handler 發(fā)送消息在主線程中處理——調(diào)用訂閱者的事件響應(yīng)函數(shù)。顯然,MainThread類的方法也不能有耗時(shí)操作,以避免卡主線程。適用場(chǎng)景:必須在主線程執(zhí)行的操作;
- BackgroundThread:在后臺(tái)線程中執(zhí)行響應(yīng)方法。如果發(fā)布線程不是主線程,則直接調(diào)用訂閱者的事件響應(yīng)函數(shù),否則啟動(dòng)唯一的后臺(tái)線程去處理。由于后臺(tái)線程是唯一的,當(dāng)事件超過(guò)一個(gè)的時(shí)候,它們會(huì)被放在隊(duì)列中依次執(zhí)行,因此該類響應(yīng)方法雖然沒(méi)有PostThread類和MainThread類方法對(duì)性能敏感,但最好不要有重度耗時(shí)的操作或太頻繁的輕度耗時(shí)操作,以造成其他操作等待。適用場(chǎng)景:操作輕微耗時(shí)且不會(huì)過(guò)于頻繁,即一般的耗時(shí)操作都可以放在這里;
- Async:不論發(fā)布線程是否為主線程,都使用一個(gè)空閑線程來(lái)處理。和BackgroundThread不同的是,Async類的所有線程是相互獨(dú)立的,因此不會(huì)出現(xiàn)卡線程的問(wèn)題。適用場(chǎng)景:長(zhǎng)耗時(shí)操作,例如網(wǎng)絡(luò)訪問(wèn)。
這里我們可以看到從最開始eventbus就通過(guò)反射將需要調(diào)用的函數(shù)加載到eventbus的類里保存下來(lái)了。不過(guò)這里也可以知道其實(shí)eventbus也只是通過(guò)handler來(lái)調(diào)用主界面的線程。秘密揭開了,自己也可以嘗試寫一套。