Guava: 事件總線EventBus

  EventBus 直譯過來就是事件總線,它使用發佈訂閱模式支持組件之間的通訊,不須要顯式地註冊回調,比觀察者模式更靈活,可用於替換Java中傳統的事件監聽模式,EventBus的做用就是解耦,它不是通用的發佈訂閱系統,也不能用於進程間通訊。可用於Android的EventBus庫主要有這幾個:Google出品的Guava,Guava是一個龐大的庫,EventBus 只是它附帶的一個小功能,所以實際項目中使用並很少。用的最多的是greenrobot/EventBus,這個庫的優勢是接口簡潔,集成方便,可是限定了方法名,不支持註解。另外一個庫square/otto修改自 Guava ,用的人也很多。spring

 以greenrobot/EventBus 爲例,咱們看一下 EventBus 模式的典型用法:緩存

// 註冊EventBus,接受事件
class Fragment {
    public void onCreate(){
       EventBus.getDefault().register(this);
    }
    public void onDestroy(){
       EventBus.getDefault().unregister(this);
    }
    public void onEvent(SomeEvent1 event){
        // handle event
    }
}

// 處理任務,發送事件
public class Service {
    public void doSomeThing(){
        // do your work
        // send event
        EventBus.getDefault().post(new SomeEvent1());
    }

關於EventBus中的幾個問題?app

  1. 事件定義:任意的對象便可;
  2. 事件處理器的註冊:事件處理的方法,添加註解便可,而後事件處理器的對象註冊到總線中,總線維護一個事件和事件處理器的關聯關係,在內存中;
  3. 事件的處理過程:同步處理和異步處理,事件提交以後,事件隊列維護在本地緩存,同步的方式直接當前線程去執行,異步的處理策略是在初始化事件總線的時候就搞了一個線程池出來,由線程池去異步執行;
  4. EventBus就開放了三個方法,register/post/unregister
  5. 爲何會有unregister?在99.99%的使用場景中,是不會在runtime的時候去register/unregister某個observer的,在spring的環境,也是在init的時候作register/unregister。不過作framework就必需要考慮這0.01%的使用場景。

1、Guava EventBus 觀察者模式異步

  首先,咱們聲明一個Observer:post

public class EventObserver {
  @Subscribe public void onMessage(Message message) {
    ...
  }
 }

 這個類並無繼承任何接口,只是在用來響應通知的方法上聲明瞭一個@Subscribe。ui

  使用EventBus很簡單,先聲明一個:this

EventBus eventBus = new EventBus();

 而後,把咱們寫好的Observer註冊進去:線程

eventBus.register(new EventObserver());

 當要通知Observer時,咱們只要這樣便可:設計

eventBus.post(message);

 

   這裏,咱們並無告訴EventBus,咱們要處理的是一個Message類型,只是在EventObserver的onMessage方法的接口聲明上使用了這個類型而已。可是,當咱們把消息發送出去的時候,它會根據類型進行匹配,保證咱們的消息正確地發送到對應的地方。orm

   相比於JDK原有的實現,這個實現會更簡單。EventObserver再也不須要存在一個繼承體系中,而繼承老是一種枷鎖,把咱們套牢在一個體系之中:

  • 咱們沒必要遵循一個特定的名字,好比Observer的update,而這裏的名字onMessage是咱們本身起的。
  • 咱們沒必要遵循特定的類型,好比update方法中做爲被觀察對象Observable和做爲參數的Object,而是根據咱們本身的需求選擇的類型。

   這種變換讓靜態類型的Java語言,有了一些動態類型的特質,也讓程序更加靈活。這種靈活性多半要歸功於Annotation,它在很大程度上影響了Java的程序設計風格。

   除了標準的EventBus,Guava還提供了另一個AsyncEventBus,從名字就能夠看出,這是一個異步的EventBus,也就是說,消息扔給它以後,會當即返回,至於Observer何時處理,那就是它的事情了。當處理耗時的處理時頗有用,咱們要依賴Executors來實現異步事件總線。

  AsyncEventBus eventBus = new AsyncEventBus("test", Executors.newCachedThreadPool());

另外:關於EventBus的使用請參見:http://blog.mcxiaoke.com/2015/08/03/how-to-write-an-eventbus-part1/

2、示例

一、一個事件的定義(任何對象均可以是事件)

public class SignEvent {    

    private String companyName; 

    private String signName;    

    private Date signDate; 

    public SignEvent(String name,String signName, Date signDate) { 

        super(); 

        this.companyName = name; 

        this.signName = signName; 

        this.signDate = signDate; 

    }   

    public String getMessage(){ 

        StringBuilder sb = new StringBuilder(); 

        sb.append("物流公司:").append(this.companyName); 

        sb.append("簽收人:").append(signName).append(",簽收日期:").append(signDate); 

        return sb.toString(); 

    } 

}

 二、定義兩個事件監聽器,添加註解作事件的訂閱

public class YTOEventListener { 

    @Subscribe 

    public void consign(SignEvent signEvent){ 

        if(signEvent.getCompanyName().equalsIgnoreCase("YTO")){ 

            System.out.println("YTO。。。開始發貨"); 

            System.out.println(signEvent.getMessage()); 

        } 

    } 

     

    @Subscribe 

    public void delivery(SignEvent signEvent){ 

        if(signEvent.getCompanyName().equalsIgnoreCase("YTO")){ 

            System.out.println("YTO。。。開始投遞"); 

        } 

    } 

}
 

public class SFEventListener {  

    @Subscribe 

    public void consign(SignEvent signEvent){ 

        if(signEvent.getCompanyName().equalsIgnoreCase("SF")){ 

            System.out.println("SF。。。開始發貨"); 

            System.out.println(signEvent.getMessage()); 

        } 

    }   

    @Subscribe 

    public void delivery(SignEvent signEvent){ 

        if(signEvent.getCompanyName().equalsIgnoreCase("SF")){ 

            System.out.println("SF。。。開始投遞"); 

        } 

    } 

} 

 三、EventBus的例子,包含時間的註冊以及事件的提交

public class EventBusTest { 
 
    public static void siginalThreadConsumer(){ 

 

        EventBus bus = new EventBus("iamzhongyong");        

        SFEventListener sf = new SFEventListener(); 

        YTOEventListener yto = new YTOEventListener(); 

        bus.register(sf); 

        bus.register(yto);      

        SignEvent sign1 = new SignEvent("SF","比熊啊",new Date()); 

        bus.post(sign1);        

        SignEvent sign2 = new SignEvent("YTO","你妹的",new Date()); 

        bus.post(sign2);    

    } 

     

    public static void multiThread(){ 

        EventBus bus = new AsyncEventBus(Executors.newFixedThreadPool(3));      

        SFEventListener sf = new SFEventListener(); 

        YTOEventListener yto = new YTOEventListener(); 

        bus.register(sf); 

        bus.register(yto); 

        SignEvent sign1 = new SignEvent("SF","比熊啊",new Date()); 

        bus.post(sign1);        

        SignEvent sign2 = new SignEvent("YTO","你妹的",new Date()); 

        bus.post(sign2);    

    } 

 

    public static void main(String[] args) {        

        EventBusTest.siginalThreadConsumer(); 

        EventBusTest.multiThread(); 

    } 

}
相關文章
相關標籤/搜索