1. 程式人生 > >EventBus--事件匯流排:觀察者模式的拓展

EventBus--事件匯流排:觀察者模式的拓展

為何要使用

android應用開發中,經常會涉及Activity,Fragment,Service等不同元件或者模組之間的訊息傳遞。使用傳統的方法實現,往往程式碼不夠優雅,而且不同元件和模組之間的耦合嚴重。隨著模組的增多、程式碼邏輯的不斷新增和修改,整個程式碼的架構就會顯得越來越混亂。為了便於理解,下面舉例說明:

例1

Activity中的不同的fragment之間需要進行通訊,傳統的做法是 將activity作為中介,Fragment A通過getActivity()獲取宿主的Activity例項進而可以拿到Fragment B的例項,從而向Fragment B傳送訊息或者獲取資料。好一點的做法是在Fragment中編寫介面,讓宿主Activity實現該介面,從而在Activity中實現不同Fragment之間的資料通訊。
如連結:

https://blog.csdn.net/yangyin3096/article/details/51476453

例2

多個Activity頁面跳轉和資料回傳的問題,例如Activity A跳轉到Activity B,接著跳轉到ActivityC,在C中執行一系列操作之後,需要傳遞資料或者事件給Activity A,傳統的做法是進行介面回撥,這樣不僅增加邏輯複雜性,而且增大頁面間的耦合。

為了解決上面的問題,實現元件間和模組間的解耦,我們引入事件匯流排的概念。

原理

事件匯流排,是訊息或者說事件流動的管道,不同元件和模組之間的訊息傳遞都是通過事件匯流排來實現,元件與元件,模組與模組之間不直接進行通訊。
事件匯流排是基於觀察者模式思想實現的,它使用釋出訂閱的方式支援元件和模組間的通訊,摒棄了觀察者模式需要顯示註冊回撥的缺點,同時可用於替換java中傳統的事件監聽方式。

  • 事件Event
    一個普通的POJO類,只包含資料,不包含對資料的操作。事件有兩種型別:普通事件和粘滯事件。粘滯事件的特點是事件釋出後,訂閱者才開始訂閱該型別事件,那麼它依舊可以收到這個事件,而普通事件是收不到的。

  • 訂閱者Subscriber
    訂閱某種型別事件的物件。通常會有一個回撥函式用於對接收到的事件進行處理,訂閱者可以訂閱事件,也可以去掉訂閱的事件。訂閱者可以引入優先順序的概念,優先順序高的訂閱者可以優先接收到該事件,並可以決定是否繼續傳遞事件給低優先順序的訂閱者。

  • 釋出者
    事件的源頭,釋出某種型別事件的物件

  • 匯流排EventBus
    負責訂閱者,事件等資訊的儲存,同時處理事件的流動和分發,通過匯流排,訂閱者和釋出者是解耦的,互相不知道對方的存在。

這裡寫圖片描述

EventBus四種ThreadMode

EventBus 3.0有以下四種ThreadMode:

  • POSTING(預設):如果使用事件處理函式指定了執行緒模型為POSTING,那麼該事件在哪個執行緒釋出出來的,事件處理函式就會在這個執行緒中執行,也就是說釋出事件和接收事件在同一個執行緒。線上程模型為POSTING的事件處理函式中儘量避免執行耗時操作,因為它會阻塞事件的傳遞,甚至可能會引起ANR。

  • MAIN:事件的處理會在UI執行緒中執行,事件處理時間不能太長,長了會ANR。

  • BACKGROUND:如果事件是在UI執行緒中釋出出來的,那麼該事件處理函式就會在新的新的執行緒中執行,如果事件本來就是子執行緒中釋出出來的,那麼該事件的處理函式直接在釋出時間的執行緒中執行。在此事件處理函式中禁止對UI進行更新操作。

  • ASYNC:無論事件在哪個執行緒中釋出,該事件處理函式都會在新建的子執行緒中執行,同樣,此事件處理函式中禁止進行UI更新操作。

觀察者、Eventbus和本地廣播的使用選擇

一般認為本地廣播是三種方式中消耗時間空間最多的一種方式,但也是android相性最好的方式。因為廣播屬於android四大元件之一,在BroadcastReceiver中的onReceive方法中可以獲得Context、Intent引數。持有這兩個引數便可以呼叫許多android sdk中的方法,這一優勢另外兩種方式很難彌補。無論是EventBus還是觀察者,需要獲得Context的話,往往都需要進行復雜的引數傳遞或者依賴注入。
本地廣播的另一個優點是,許多系統級的事件都是使用廣播來進行通知的,像常用的電量變化、網路狀態變化、簡訊傳送接受的狀態等等。這就使得與android系統相關的通知,廣播往往成了唯一的選擇。

但這並不意味著android系統中的通知都應該使用廣播,因為相對於其他的方式而言,廣播是重量級的、消耗資源較多的方式。廣播的優勢體現在它與android sdk連結的更緊密,當我們需要同android互動的時候,廣播提供的便捷性抵消了它過多的資源消耗。但是對於不需要同android互動或者只是做很少的互動的時候,使用廣播往往是一種浪費。

Eventbus作為android開發中的常用框架,擁有著許多優點:

  • 排程靈活

不依賴於Context,使用時無需像廣播一樣關注Context的注入與傳遞。父類對於通知的監聽和處理可以繼承給子類。這對於簡化程式碼至關重要。通知的優先順序,能夠保證Subscriber關注最重要的通知;粘滯事件能夠保證通知不會因Subscriber的不在場而忽略。
可繼承,優先順序,粘滯是eventBus比之於廣播,觀察者等方式最大的優點,他們使得建立結構良好組織緊密的通知系統成為可能。

  • 使用簡單

Eventbus的Subscriber註冊非常簡單,呼叫eventBus物件的register方法即可,如果不想建立eventBus還可以直接呼叫靜態方法EventBus.getDefault()獲取預設例項,Subscriber接收到通知之後的操作放在onEvent方法裡就行了。成為Publisher的過程更簡單,只需要呼叫合適的eventBus(自己建立或者是預設的)的post方法即可。

  • 快速且輕量

作為github的明星專案之一,EventBus的原始碼中許多技巧來改善效能,

觀察者這種設計模式應該屬於程式設計師的基本功,由於觀察者的實現比較簡單,因此效能上是三者中最好的,但是觀察者難以控制通知的優先度,特別是一開始沒有考慮優先度中途更高需求又加入優先度。另外觀察者模式要求觀察者在事件發生時在場才能收到通知,這就是的觀察者有可能遺漏事件。客觀來說,這並不能算觀察者的缺點,因為其他的方式往往也是這樣,更加嚴謹的說法是觀察者沒有Eventbus優先順序、粘滯事件的優點。

總結

事件匯流排使用起來很方便,但是我們不應該濫用它,需要嚴格限定它的使用範圍。只有在元件或者模組間通訊的時候才使用它,對於簡單的訊息傳遞,就選用觀察者模式或者事件回撥的方式即可。