使用otto通常是通過乙個provider提供乙個bus單例。
首先我們來分析一下bus的建構函式,bus類的建構函式最終都會呼叫bus(threadenforcer enforcer, string identifier, handlerfinder handlerfinder)這個建構函式。
其中enforcer用來限制執行register,unregister以及post event的執行緒,如果執行這些函式的執行緒不是enforcer指定的執行緒,就會丟擲異常。
identifier相當於給bus起的乙個名字,在tostring方法中使用。
handlerfinder是整個event bus的核心,用於在register,unregister的時候尋找所有的subscriber和producer。handlerfinder不需要使用者指定,預設使用handlerfinder介面中定義的常量annotated,annotated本身就是handlerfinder的匿名實現。
如果乙個類對某些事件感興趣,需要呼叫register方法來註冊監聽這些事件,監聽通過在方法上使用@subscribe來實現,otto通過方法的引數來決定是否呼叫該方法。
register方法首先會呼叫handlerfinder的findallproducers(object)方法去找到所有使用了@produce註解的方法。findallproducers其實是委託annotatedhandlerfinder.findallproducers方法。在annotatedhandlerfinder中,定義了乙個靜態變數subscribers_cache
private static final map, map, method>> producers_cache =
new hashmap, map, method>>();
producers_cache 的key是監聽類,就是呼叫bus.register()的類,value本身又是乙個map,這個map的key是事件的class,value是生產事件的方法。
比如下面這個例子:
public class mainactivity extends activity
@produce public clickevent produceclick()
}
在producers_cache中就會有一條記錄,它的key是mainactivity.class,value對應的map中,key是clickevent.class,value是produceclick method物件。
subscribers_cache:
mainactivity.class -》
clickevent.class -》produceclick
當呼叫annotatedhandlerfinder的findallproducers方法時,會先根據傳入的物件的型別,檢查是否已經被快取到producers_cache,如果沒有的話,就會呼叫loadannotatedmethods,利用反射去尋找所有使用了@produce註解的方法,並且將結果快取到producers_cache中。最後,會從producers_cache中取出監聽類的所有produce方法,遍歷這些方法,為乙個方法構建乙個eventproducer物件,並將這個eventproducer物件放到乙個以事件的class作為key的map中,然後返回這個map。eventproducer類包含了produce方法和該方法所屬的物件,並且提供了呼叫produce方法的功能。
回到bus的register方法,呼叫完findallproducers方法之後,會遍歷傳入的監聽類的produce方法,並且根據produce方法的返回值型別,來檢查是否已經有對應的subscribe存在,如果有的話,就會呼叫subscribe方法,並將producer的返回值傳入。
sethandlers = handlersbytype.get(type);
if (handlers != null && !handlers.isempty())
}
這裡需要注意的是,bus物件兩個map型別的常量,用來快取所有事件的producer和subscriber。
/** all registered event handlers, indexed by event type. */
private final concurrentmap, set> handlersbytype =
new concurrenthashmap, set>();
/** all registered event producers, index by event type. */
private final concurrentmap, eventproducer> producersbytype =
new concurrenthashmap, eventproducer>();
從定義我們可以看出,一種事件只能有乙個producer,卻可以有多個subscriber。
找到了所有的producers之後,就是呼叫handlerfinder.findallsubscribers(object)來尋找object中使用@subscribe註解的方法,過程和findallproducers類似,唯一的不同是乙個事件可以有多個subscriber,因此findallsubscribers的返回值型別是map, set>。其中eventhandler包含了subscribe方法和訂閱事件的物件的資訊。
找到監聽類所有的subscribe方法之後,就需要檢視bus中時候有和這些subscribe方法對應的producer方法,如果有的話,就會使用呼叫subscribe方法。這也就是文件上說的,一旦有新的subscriber訂閱了某一事件,並且該事件有對應的producer,那麼subscriber方法就會被立即呼叫,並且傳入producer方法的返回值。
post(obejct event)方法用來傳送事件給所有訂閱者,它接收乙個object型別的引數,說明otto的事件可以是任意型別的物件。post方法首先會獲取所有event物件的父類
set> dispatchtypes = flattenhierarchy(event.getclass());
然後遍歷這些父類,找到他們的所有訂閱者,傳送事件。這表明任何訂閱了event物件父類的訂閱者也都會收到event事件。值得注意的是otto使用threadlocal型別來存放事件佇列threadlocal> eventstodispatch,這樣極大的簡化了多執行緒模式下的開發。
unregister方法,做的事情和register剛好想法,從快取中清除所有和當前監聽物件相關的producers和subscribers。
spring原始碼分析 spring原始碼分析
1.spring 執行原理 spring 啟動時讀取應用程式提供的 bean 配置資訊,並在 spring 容器中生成乙份相應的 bean 配置登錄檔,然後根據這張登錄檔例項化 bean,裝配好 bean 之間的依賴關係,為上 層應用提供準備就緒的執行環境。二 spring 原始碼分析 1.1spr...
思科VPP原始碼分析(dpo機制原始碼分析)
vpp的dpo機制跟路由緊密結合在一起。路由表查詢 ip4 lookup 的最後結果是乙個load balance t結構。該結構可以看做是乙個hash表,裡面包含了很多dpo,指向為下一步處理動作。每個dpo都是新增路由時的乙個path的結果。dpo標準型別有 dpo drop,dpo ip nu...
redux原始碼分析(三) 原始碼部分
下面是每個部分的一些解讀 createstore apicreatestore reducer,initialstate enhancer 曾經非常好奇這個函式的第二個引數到底是initialstate還是enhancer,因為見過兩種寫法都有的,以為是版本問題。看了原始碼才發現,都可以的。如果你不...