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和源碼注釋