EventBus & Otto的使用和比較

EventBus主要用來消息/事件的傳遞,卻能實現組建之間的解耦。對比其他的消息傳遞:
  • ** 使用監聽器接口(Listener Interface):**

1、一個實現了監聽器接口的類,必須把它自身注冊到它想要監聽的類中去。這就使監聽與被監聽之間保持強關聯關系,而且不利于單元測試。

2、對比:而EventBus則起到了橋梁作用,想要監聽什么對象/事件,在EventBus中去注冊(register(Object));想要發送某事件的消息,使用EventBus去post(post(Event))。這樣便通過EventBus實現了監聽者和被監聽者的解耦。

  • ** 使用廣播(BroadCastReciver): **

1、使用廣播的代碼臃腫(還有一種說法:它們內部的實現都需要IPC,單從傳遞效率上來講,可能并不太適合上層的組件間通信),而且Intent傳遞數據時,在編譯時并不能檢查出所設的extra類型與收到時的類型一致。所以一個很常見的錯誤便是你或者你團隊中的其他人改變了Intent所傳遞的數據,但忘記了對全部的接收器(receiver)進行更新。這種錯誤在編譯時是無法被發現的,只有在運行時才會發現問題。

2、對比:使用EventBus所傳遞的消息/事件,是我們自己定義的Event類,由于接受方和發送方都是與這些類實例打交道,所以所有的數據都可以進行類檢查,這樣任何由于類型不一致導致的錯誤都可以在編譯期被發現。

  • startActivityForResult()和onActivityResult()方法:

1、傳統的Activity間的消息傳遞便是通過
startActivityForResult和onActivityResult,會產生較多的狀態或邏輯判斷,而且Intent或Bundle傳值還得檢測類型,容易發生錯誤。更復雜些的場景,比如A啟動B,B啟動C,在C中用戶的操作需要更新A和B,那么判斷邏輯就更麻煩了。

2、對比:使用EventBus可以很簡單地解決以上問題,能夠擺脫Activity間通信使用onActivityResult的方法,同樣可以擺脫Fragment間通信通過宿主Activity使用Interface的方式,還有Fragment和Activity間通信使用Interface的方式。

EventBus可以用來處理異步并發消息。

Android中有很多執行異步操作的方法:AsyncTask、Loader、Executor等。

  • ** AsyncTask **
    AsyncTask被設計成為一個工具類,要求我們盡量執行一些短小的操作,如果需要在線程中執行較長時間的任務,那么建議直接使用java.util.concurrent包中提供的各種API,如Executor、 ThreadPoolExecutor以及FutureTask。

  • ** Loader **
    Android 3.0引入了Loader,來解決Activity/Fragment生命周期的問題,但Loader仍然要維持Activity/Fragment中的callback接口LoaderManager.LoaderCallbacks(其中包含onCreateLoader()、onLoadFinished()和onLoaderReset方法),在onCreateLoader()中要實現自己的DataLoader,可以繼承抽象類AsyncTaskLoader<T>拓展泛型并覆寫其loadInBackground()方法。

  • ** EventBus **
    EventBus中內置了并發處理機制,既支持工作線程向UI線程發送消息/事件,也支持從主線程發消息,工作線程來處理響應。

1、onEvent(T event)對應ThreadMode.PostThread。該方法的執行和事件發送者在同一個線程中,適用于對是否在主線程執行無要求的情況,但post線程為主線程,則不能有耗時操作。

2、onEventMainThread(T event)對應ThreadMode.MainThread。在主線程執行,不論事件從哪個線程發送過來。

3、onEventBackgroundThread(T event)對應ThreadMode.Background Thread如果發送事件的線程不是UI線程,則運行在該線程中。如果發送事件的是UI線程,則它運行在由EventBus維護的一個單獨的線程中。多個事件會同步地被這個單獨的后臺線程所處理。適用于輕微耗時的操作,比如讀寫數據庫。

4、onEventAsync(T event)對應ThreadMode.Async。運行在單獨的工作線程中,不論發送事件的線程是否為主線程。跟BackgroundThread不一樣,該模式的所有線程是獨立的,因此適用于長耗時操作,例如網絡訪問。

這樣通過EventBus就可以不用維護引用和回調接口,從而實現組件間的消息/事件傳遞。

EventBus處理網絡請求并通知UI

因為EventBus提供了多種ThreadMode,我們完全也可以使用EventBus來處理耗時操作。比如在打開一個Activity時,我們暫稱為“A”,它會從服務端獲取數據并進行顯示,我們首先注冊EventBus;然后定義onEventMainThread(Response data)方法,接收請求到的數據并刷新界面;另外,還需要調用post(Request rq)來通知我們定義的RequestManger來訪問網絡并請求數據,當然RequestManger注冊并定義了onEventAsync(Request rq)方法,我們在該方法中請求網絡數據并最后調用EventBus.post(Response data)方法去通知“A”刷新UI。

EventBus默認創建了線程池為Executors.newCachedThreadPool(),Async和Background模式下都是使用該線程池執行任務,當然我們可以根據情況去定義自己的ExecutorService。

EventBus的一些局限(因為3.0版本有較大的更新,因此以下有些觀點是陳舊的,已做更正)

1、EventBus是采用反射的方式對整個注冊的類的所有方法進行掃描來完成注冊,當然會有性能上的影響。[3.0中EventBus提供了EventBusAnnotationProcessor注解處理器來在編譯期通過讀取@Subscribe()注解并解析、處理其中所包含的信息,然后生成java類(默認EventBusIndex類在build文件夾中)來保存所有訂閱者關于訂閱的信息,這樣就比在運行時使用反射來獲得這些訂閱者的信息速度要快]
2、EventBus必須定義以onEvent開頭的幾個方法,代碼中語境比較突兀,且有可能會導致拼寫錯誤。[EventBus 3.0支持注解方式,而且支持注解中設置ThreadMode、sticky事件、優先級],like this:

@Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true, priority = 100)
public void test(String str) { 
}

3、用EventBus來處理網絡請求太過簡單粗暴,考慮使用Volley處理網絡請求,volley支持請求緩存、請求隊列和請求優先級,代碼的結構清晰、擴展性強,很適合客戶端輕小的請求。關于Volley可以看我的 Volley Demo和源碼注釋

更好的解決方案(推薦使用EventBus 3.0)

1、Otto同樣是事件總線框架(Otto Demo和源碼注釋),滿足消息/事件傳遞的同時,也實現了組件間的解耦。跟EventBus一樣,采用反射的方式對注冊類中的所有方法進行掃描和調用。
2、Otto不同于EventBus的是,它使用注解的方式(@Subscribe、@Produce)來標注方法,這一點比EventBus優雅。
3、Otto沒有像EventBus那樣強大實現了4種ThreadMode,Otto中在接口ThreadEnforcer以及內部的實現域ANY和MAIN,在MAIN內部有一個是否是主線程的檢查,而ANY不做任何檢查的事情。因此Otto更多的使用場景是在主線程中,相對是輕量級的。
4、綜合上面EventBus處理網絡請求的缺陷,因此我覺得比較合理的方案是,使用Volley+Otto組合的方式來處理異步網絡請求和UI更新,以及組件間的消息傳遞。
5、EventBus 3.0版本支持注解以及在編譯期掃描事件訂閱方法,性能上有較大提升,因此推薦使用EventBus 3.0版本。(這里有EventBus的官方性能測試對比報告:https://github.com/greenrobot/EventBus/blob/master/COMPARISON.md

更多可以參考我的:EventBus Demo和源碼注釋

轉載請標明出處:http://www.lxweimin.com/p/cb39a0018db1

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,748評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,165評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,595評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,633評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,435評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,943評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,035評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,175評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,713評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,599評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,788評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,303評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,034評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,412評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,664評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,408評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,747評論 2 370

推薦閱讀更多精彩內容

  • 文章基于EventBus 3.0講解。首先對于EventBus的使用上,大多數人還是比較熟悉的。如果你還每次煩于使...
    Hohohong閱讀 2,314評論 0 6
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,600評論 25 707
  • 前言:EventBus出來已經有一段時間了,github上面也有很多開源項目中使用了EventBus。所以抽空學習...
    Kerry202閱讀 1,293評論 1 2
  • 最近在項目中使用了EventBus(3.0),覺得非常好用,于是就看了一些關于EventBus源碼分析的文章,現在...
    shenhuniurou閱讀 1,514評論 0 4
  • 我不甘于旅行 所以戈壁灘上的那堆柴火 誰愛點燃誰去點 我在流動的金色沙粒中 憑心而論 若就這樣睡著 總比死在大地上...
    在山閱讀 420評論 0 0