EventBus,也即事件總線。在wiki上有關於Event Monitor的一個說法:java
Event monitoring makes use of a logical bus to transport event occurrences from sources to subscribers, where event sources signal event occurrences to all event subscribers and event subscribers receive event occurrences.
事件監聽器經過邏輯總線來將發生的事件從發生源傳輸到訂閱者。事件發生源在事件發生的時候可以發出信號給全部訂閱者,訂閱者則可以接收到發生的事件。android
我的猜想事件總線這種說法源至於計算機內經常使用的幾個總線結構【好比CPU總線,IO總線等】。他們有一個共同的特定就是負責傳遞某種 object 到指定的地方。好比數據總線負責的是CPU到RAM,地址總線負責的是RAM到RAM傳遞數據。git
這條詞條的分類是在操做系統這個目錄下,這也能夠理解成是在操做系統較早地使用了這種模式。
在Java內置的包中也有一種EventBus,但它是基於接口的。Google在Guava中實現了一套本身的EventBus,Google實現的總線庫更具可讀性,由於它使用Annotion標記訂閱者和生產者,方法名能夠自定義,更具意義。github
在這裏先說說Android內置的兩種跟EventBus相似的機制。Intent和BroadcastReceiver。
這二者均可以起到跟事件總線相似的效果。註冊廣播接收器和單純發一個intent就能夠喚起其餘組件,提醒其餘組件更新,這是很是方便的,同時也是下面提到的兩個開源方案所作不到的。
但這種機制也有很差地方,它們內部的實現都須要 IPC,雖然Android的Binder
使得IPC簡單了點~~(仍是蠻複雜的吧)~~,但傳遞效率上會是個問題。若是本身徹底不須要IPC,下面說到的兩個項目會更加適合。
在Android中彷佛就只有兩個Eventbus的開源項目,Square的otto和GreenRobot的EventBus(如下稱GEventBus)。ide
otto是square開源的一個基於Guava的EventBus的項目。跟Guava同樣,otto使用Annotion做爲事件的標記,@Subscribe
即事件的處理者,@Produce
是基本事件的生產者。舉個官方給的例子:函數
<!-- lang: java -->post
@Subscribe public void answerAvailable(AnswerAvailableEvent event) { // TODO: React to the event somehow! } @Produce public AnswerAvailableEvent produceAnswer() { return new AnswerAvailableEvent(this.lastAnswer); } // 訂閱者和發佈者均須要向同一個總線註冊 bus.register(this);
使用起來就是這麼簡單。訂閱者向總線註冊,若是此時存在一個生產者,那麼這個生產者的方法會被調用以產生一個初始對象來初始化訂閱者。另外,在總線接收到對應的事件以後,訂閱者的方法就也會被調用。this
bus.post(new AnswerAvailableEvent(100));
post事件並不須要對象向總線註冊。post事件後,若是存在事件的訂閱者那麼訂閱者的方法就會被調用。若是不存在訂閱者,那麼事件會被包裹成DeadEvent
重拋。(待作文章細說)。 默認狀況下,otto只支持主線程的事件。好比下面代碼所示,bus1和bus2是等價的。若是將策略設置爲ANY,那麼也能夠在非主線程執行。只是不建議,這個庫適合的場景也就只是在主線程而已,其餘環境下會出現什麼情況不作保證。google
Bus bus1 = new Bus(); Bus bus2 = new Bus(ThreadEnforcer.MAIN); // Bus bus3 = new Bus(ThreadEnforcer.ANY);
要想在基類中註冊事件要花點心思。(不能經過this來向bus註冊事件,由於在子類中的方法調用super到父類方法時,this指的永遠是子類)。要想在基類註冊事件,基本上只能寫一個成員變量,在變量內部註冊方法。邏輯會略奇怪。另外,可能須要本身實現一個BusProviderurl
greenrobot的另外一個比較出名的開源項目(另一個是greenDAO)。一樣是EventBus,但這個項目不是基於Annotion的。由於Android的Runtime Annotion處理起來效率實在是不高,尤爲是在4.0以前。在4.0以後也不見得效率有多大提升。
GEventBus使用的是字符串匹配,默認訂閱者會調用帶onEvent
或者說是EventBus類裏面的DEFAULT_METHOD_NAME
做爲前綴的方法。只有仔細跟蹤代碼以後,你纔會發現它的幾種線程模型是這麼用的:
public void onEvent(SimpleEvent event) {}; public void onEventBackgroundThread(SimpleEvent event) {}; public void onEventMainThread(SimpleEvent event) {}; public void onEventAysnc(SimpleEvent event) {};
其餘操做跟otto相似。只是GEventBus不支持生產者方法。(題外話:我是看了otto的demo以後才知道GEventBus的通常用法= =)
onEvent*
方法,不然程序就會崩掉。解決方案,也算有吧,本身實現了一個蠻挫的暫時性解決方案 issus98RuntimeException
,我始終以爲GEventBus有問題。注意如下會有不少我的的喜愛致使的吐槽=_=
我的以爲最純正的是otto,即便GreenRobot的EventBus稱它的效率比前者高出許多(有benchmark,因此算是事實)。可是一個開源項目,看的並不僅是效率問題吧。
在知乎上看到過一個問題:一個開源軟件爲什麼成功。一個好的開源項目也是同理,其中有個答案提到的幾點我很是贊同。
在發現沒有Demo以後,我研究過GEventBus的代碼。邏輯是搞懂了,但也發覺了GEventBus的代碼是如此地不友好,沒有關鍵的註釋,名字又表意不清。最最沒法容忍的是,它將一堆函數標記爲@depreated
,即便如今只能用它們來作。這個Annotion是來這麼用的嗎?提供了新的替代接口再標記爲廢棄如何?或者你乾脆設置成private好麼。
看otto的代碼是享受,雖然我只是稍微看了一下,沒有深刻去研究。Square彷佛還爲otto開發了IntellJ的plugin,能夠快速地瀏覽全部的訂閱者和生產者,這點也是GEventBus所不及的吧。
就我的喜愛而言,果真仍是選擇otto,用annotion寫起來仍是比較順心的。不像GEventBus,居然要用那麼長的名字才能做爲事件回調。輸入越多,越容易出錯,這點不管是在用戶體驗仍是敲代碼的時候都是同理。
我的拙見,歡迎交流>_< 22:09