探究EventBus粘性事件實現機制

語言: CN / TW / HK

theme: juejin highlight: a11y-light


持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第3天,點選檢視活動詳情

眾所周知,EventBus是支援粘性事件的,即可以先發送粘性事件,然後再註冊,程式碼如下:

  1. 粘性事件觀察者 kotlin @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) fun registerEventBus(o: Any) { }

  2. 傳送粘性事件 kotlin EventBus.getDefault().postSticky(Any())

  3. 註冊EventBus kotlin EventBus.getDefault().register(this)

接下來我們就來探究下EventBus的粘性事件是如何實現的。

postSticky()內部機制

image.png 1. 如果是傳送的粘性事件,會新增到stickyEvents中,看下這個屬性的實現:

image.png
可以看到這個屬性是一個Map集合,其中key為事件型別的class物件,value為對應的事件型別。

  1. 繼續看下post(Event)方法:

image.png

  1. 首先將這個粘性事件新增到PostingThreadState(執行緒私有)的eventQueue集合中

  2. 通過isMainThread方法判斷當前是否為主執行緒,最終會呼叫到我們熟悉的Looper.getMainLooper() == Looper.myLooper()進行判斷

  3. 迴圈遍歷eventQueue佇列,不斷的取出集合元素進行分發,看下postSinleEvent()方法如何實現:

image.png

  1. 如果eventInheritance為true,會查詢當前傳送的粘性事件型別的父型別,並返回查詢到的集合

  2. 接下來就會呼叫postSingleEventForEventType()方法來進行最終粘性事件的分發,即通知通過@Subscribe註解註冊的粘性事件觀察者,看下具體實現:

image.png

  1. 呼叫subscriptionsByEventType獲取註冊該事件型別的所有訂閱方法,但是由於這個時候我們是先發送的粘性事件再註冊EventBus,而subscriptionsByEventType中集合元素的填充實在註冊EventBus發生的,所以通過subscriptionsByEventType獲取到的subscriptions將是null的,所以接下來肯定不會走下面的if程式碼塊中的邏輯了。

postSticky()小結

上面這麼多程式碼邏輯,其實只幹了一件事,就是將這個粘性事件新增到了stickyEvents這個集合中。之後的邏輯雖多,但和粘性事件沒啥關係。

register內部機制

image.png

  1. findSubscriberMethods()這個方法裡面的邏輯就不帶大家進行分析了,總之就幹了一件事情:

    查詢當前類通過@Subscribe註冊的所有事件訂閱方法,並返回一個List<SubscriberMethod>集合,其中SubscriberMethod就是對每個註冊的訂閱方法和當前註冊類的封裝

  2. subscribe這個方法是關鍵,深入探究下:

image.png

image.png

  • 第1、2、3、4步中其實就幹了兩件事情:

    • 填充subscriptionsByEventType集合,key為事件型別,value為通過@Subscribe訂閱了該事件型別的方法集合
    • 填充typesBySubscriber集合,key為註冊EventBus的類,value為該類中所有@Subscribe註解修飾的方法集合
  • 第5步就是實現粘性事件分發的關鍵地方

    • 首先判斷當前@Subscribe修飾的訂閱方法是否為粘性,即@Subscribe(sticky = true)sticky等於true
    • 是的話就從stickyEvents集合中判斷是否存在和訂閱方法中註冊的事件型別相同的事件:

      這個stickyEvents是不是很熟悉,就是我們之前傳送粘性事件時,將粘性事件新增到的方法集合

    • 如果存在,則就執行該粘性事件的分發,即呼叫執行該訂閱方法,最終會呼叫到invokeSubscriber()方法:

image.png

從上面可以看到,最終是通過反射來實現的訂閱了粘性事件方法的執行。

register小結

該方法最終會判斷當前是否存在註冊EventBus前傳送的粘性事件,且當前註冊類中存在訂閱該事件型別的方法,然後立即執行。

總結

以上就是EventBus粘性事件的內部實現機制,總體來說不算複雜,大家看著文章跟著原始碼一步步分析應該就很容易理解這部分實現邏輯了。