事件总线模式
一、為何使用EventBus
今天我們介紹一個將耦合度降到極低的框架EventBus。
在這之前處理APP全局的監聽,大多時候用的是BrodercastReceiver來實現時間的監聽。但用起來很不方便,?
BrodercastReceiver在APP中限定只監聽系統的廣播事件(如:電量,網絡等)就OK了。在一些模塊或組件之間的時間傳遞大多用的觀察者,在使用的過程中你會發現一個個的回掉,各式各樣的參數弄得你頭暈目眩。那我們就接觸好的框架解決開發中遇見的問題,讓自己更輕松的開發。
二、EventBus原理分析
EventBus基于觀察者模式的Android事件分發總線。通過事件總線可以實現Activity、Fragment、Service等不同模塊或組件之間的通信。避免不同組件和模塊之間的耦合問題。方便代碼的維護與理解。
事件總線是基于觀察者模式的思想實現的,它使用發布訂閱的方式支持組件和模塊間的通信,摒棄了觀察者模式需要顯示注冊回調的缺點,同時可用于替換Java中傳統的事件監聽方式。
發布者Publisher:發布某種事件的對象。
事件Event:一個簡單的POJO對象。只包含數據,不對數據進行處理。
事件總線EventBus:?負責存儲時間信息,處理事件的流動和分發,通過時間總線,事件發布者與訂閱者互相不知道對方的存在,是解耦的。事件被發布到總線上({@link #post(Object)})到總線,它將它傳遞給具有事件類型匹配處理程序方法的訂閱服務器。要接收事件,訂閱者必須使用{@link #register(Object)}向總線注冊自己。注冊之后,訂閱者將收到事件,直到調用{@link #unregister(Object)}。事件處理方法必須由 {@link Subscribe}必須是public,返回非(空),并且只有一個參數 (事件)。
訂閱者Subscriber:?訂閱某個事件,一般情況會有一個回掉函數處理接收到的事件。訂閱者通過{@link #register(Object)}向總線注冊自己,即為訂閱事件。訂閱者也可以直到調用{@link #unregister(Object)}取消事件訂閱。
三、EventBus開源庫使用(來自greenrobot/EventBus)
優點:?
1.簡化組件之間的通信?
2.分離事件發送器和接收器?
3.對activity、fragment和線程進行良好的執行?
4.避免復雜和容易出錯的依賴關系和生命周期問題。?
5.快速;專為高性能優化?
6.體積小(<50k)
Android studio & Gradle使用分為以下幾步:
0.在Gradle中添加在線依賴。
compile 'org.greenrobot:eventbus:3.0.0'- 1
- 2
1.定義消息事件MessageEvent,也就是創建事件類型
public static class MessageEvent { /* Additional fields if needed */ }- 1
2.選擇你要訂閱的訂閱者(subscriber)在訂閱者里需要用注解關鍵字 @Subscribe來“告訴”EventBus使用什么方法處理event。
@Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) {/* Do something */};- 1
- 2
注冊與注銷訂閱者。 通常在Android activity與fragment生命周期中注冊與注銷。
@Overridepublic void onStart() {super.onStart(); EventBus.getDefault().register(this); } @Override public void onStop() { super.onStop(); EventBus.getDefault().unregister(this); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
3.發送事件。
EventBus.getDefault().post(new MessageEvent());- 1
四、EventBus開源庫源碼解讀
首先,解讀@Subscribe,從源碼可知,主要有三個參數ThreadMode(線程通信)、Sticky(粘性)、priority(事件優先級)。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe { ThreadMode threadMode() default ThreadMode.POSTING; /** * If true, delivers the most recent sticky event (posted with * {@link EventBus#postSticky(Object)}) to this subscriber (if event available). */ boolean sticky() default false; /** Subscriber priority to influence the order of event delivery. * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of * delivery among subscribers with different {@link ThreadMode}s! */ int priority() default 0; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
ThreadMode中有四種模式
1.ThreadMode.POSTING?
默認的模式,推薦的模式。?
訂閱者將在同一線程中調用,該線程將發布事件。?
此模式完全避免了線程切換,開銷最少。
- 1
- 2
- 3
- 4
2.ThreadMode.MAIN?
用戶將在Android的主線程(有時稱為用戶界面線程)中調用。?
如果發布線程是主線程,則將直接調用事件處理程序方法。?
使用此模式的事件處理程序必須快速返回,以避免阻塞主線程。
- 1
- 2
- 3
- 4
3.ThreadMode.BACKGROUND?
如果post事件的線程不是主線程,則事件處理程序方法將直接在發布線程中調用。?
如果發布線程是主線程,則EventBus使用單個后臺線程,該線程將按順序執行所有事件。?
使用此模式的事件處理程序避免耗時操作,以避免阻塞后臺線程。
- 1
- 2
- 3
- 4
4.ThreadMode.ASYNC?
事件處理方法在單獨的線程中調用。?
發布線程和主線程始終獨立。?
發布事件不會等待事件處理程序使用此模式。?
如果事件處理程序的執行可能需要一些時間,例如網絡訪問,則事件處理程序方法應該使用此模式。?
避免同時觸發大量長時間運行的異步處理程序方法,從而限制并發線程的數量。?
EventBus使用線程池有效地重用已完成的異步事件處理程序通知中的線程。
- 1
- 2
- 3
- 4
StickyEvent(粘滯事件)
StickyEvent的特點是,訂閱者在發布事件之后訂閱該事件,還是可以收到該事件。StickyEvent在內存中保存最新的消息,取消原有消息,執行最新消息,只有在注冊后才會執行,如果沒有注冊,消息會一直保留來內存中。
//發送粘滯事件 EventBus.getDefault().postSticky(new MessageEvent());- 1
- 2
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
removeStickyEvent源代碼
/*** Remove and gets the recent sticky event for the given event type.** @see #postSticky(Object)*/public <T> T removeStickyEvent(Class<T> eventType) {synchronized (stickyEvents) { return eventType.cast(stickyEvents.remove(eventType)); } } /** * Removes the sticky event if it equals to the given event. * * @return true if the events matched and the sticky event was removed. */ public boolean removeStickyEvent(Object event) { synchronized (stickyEvents) { Class<?> eventType = event.getClass(); Object existingEvent = stickyEvents.get(eventType); if (event.equals(existingEvent)) { stickyEvents.remove(eventType); return true; } else { return false; } } }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
priority事件優先級
用戶優先級影響事件傳遞的順序。?
在同一傳遞線程({@link ThreadMode})內,更高優先級的訂閱者將在其他優先級較低的其他事件之前接收事件。?
默認優先級為0。?
注意:優先級不影響不同{@link ThreadMode}的訂閱者之間的傳遞順序!
- 1
- 2
- 3
- 4
- 5
轉載于:https://www.cnblogs.com/ziyixuedie/p/9071887.html
總結
- 上一篇: UE4物理笔记
- 下一篇: poj2823 线段树模板题 点修改(也