EventBus 直译过来就是事件总线,它使用发布订阅模式支持组件之间的通信,不需要显式地注册回调,比观察者模式更灵活,可用于替换Java中传统的事件监听模式,EventBus的作用就是解耦,它不是通用的发布订阅系统,也不能用于进程间通信。可用于Android的EventBus库主要有这几个:Google出品的Guava,Guava是一个庞大的库,EventBus 只是它附带的一个小功能,因此实际项目中使用并不多。用的最多的是greenrobot/EventBus,这个库的优点是接口简洁,集成方便,但是限定了方法名,不支持注解。另一个库square/otto修改自 Guava ,用的人也不少。

以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中的几个问题?

  1. 事件定义:任意的对象即可;
  2. 事件处理器的注册:事件处理的方法,添加注解即可,然后事件处理器的对象注册到总线中,总线维护一个事件和事件处理器的关联关系,在内存中;
  3. 事件的处理过程:同步处理和异步处理,事件提交之后,事件队列维护在本地缓存,同步的方式直接当前线程去执行,异步的处理策略是在初始化事件总线的时候就搞了一个线程池出来,由线程池去异步执行;
  4. EventBus就开放了三个方法,register/post/unregister
  5. 为什么会有unregister?在99.99%的使用场景中,是不会在runtime的时候去register/unregister某个observer的,在spring的环境,也是在init的时候做register/unregister。不过做framework就必须要考虑这0.01%的使用场景。

一、Guava EventBus 观察者模式

首先,我们声明一个Observer:

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

这个类并没有继承任何接口,只是在用来响应通知的方法上声明了一个@Subscribe。

使用EventBus很简单,先声明一个:

EventBus eventBus = new EventBus();

然后,把我们写好的Observer注册进去:

eventBus.register(new EventObserver());

当要通知Observer时,我们只要这样即可:

eventBus.post(message);

这里,我们并没有告诉EventBus,我们要处理的是一个Message类型,只是在EventObserver的onMessage方法的接口声明上使用了这个类型而已。但是,当我们把消息发送出去的时候,它会根据类型进行匹配,保证我们的消息正确地发送到对应的地方。

相比于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/

二、示例

1、一个事件的定义(任何对象都可以是事件)

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(); 

    } 

}

2、定义两个事件监听器,添加注解做事件的订阅

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。。。开始投递"); 

        } 

    } 

}

3、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(); 

    } 

}

Guava: 事件总线EventBus的更多相关文章

  1. vue中央事件总线eventBus的简单理解和使用

    公共事件总线eventBus的实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信.它是实现非父子组件通信的一种解决方案. 用法如下: 第一步:项目中创建一个js文件(我通 ...

  2. 【bird-java】分布式服务间的事件总线EventBus

    什么是EventBusEventBus是对发布-订阅模式的一种实现.其以一种非常优雅的方式实现了组件间的解耦与通信,在Android开发.DDD等领域都有非常广泛的应用. 事件流大致如下: Produ ...

  3. Android事件总线EventBus详解

    顾名思义,AndroidEventBus是一个Android平台的事件总线框架,它简化了Activity.Fragment.Service等组件之间的交互,很大程度上降低了它们之间的耦合,使我们的代码 ...

  4. 自己动手写事件总线(EventBus)

    本文由云+社区发表 事件总线核心逻辑的实现. EventBus的作用 Android中存在各种通信场景,如Activity之间的跳转,Activity与Fragment以及其他组件之间的交互,以及在某 ...

  5. C# 事件总线 EventBus

    1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对发布-订阅模式的一种实现.它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需 ...

  6. 事件总线EventBus

    什么是事件总线管理? 将事件放到队列里,用于管理和分发: 保证应用的各个部分之间高效的通信及数据,事件分发: 模块间解耦: 什么是EventBus? EventBus是发布/订阅的事件总线.Event ...

  7. ASP.NET Core基于微软微服务eShopOnContainer事件总线EventBus的实现

    这个EventBus的实现是基于微软微服务https://github.com/dotnet-architecture/eShopOnContainers项目的,我把它从项目中抽离出来,打包成nuge ...

  8. 事件总线 EventBus

    661. .net中事件模型很优雅的实现了观察者模式,同时被大量的使用在各种框架中. [2016-04-30 10:52:42]662. Prism框架中实现了一个典型的EventAggregator ...

  9. 基于ASP.NET Core 5.0使用RabbitMQ消息队列实现事件总线(EventBus)

    文章阅读请前先参考看一下 https://www.cnblogs.com/hudean/p/13858285.html 安装RabbitMQ消息队列软件与了解C#中如何使用RabbitMQ 和 htt ...

随机推荐

  1. thymeleaf中的th:remove用法

    一.删除模板片段使用th:remove属性 th:remove的值如下: 1.all:删除包含标签和所有的孩子. 2.body:不包含标记删除,但删除其所有的孩子. 3.tag:包含标记的删除,但不删 ...

  2. Git使用过程中出现项目文件无法签入Source Control的情况

    在VS中使用Git进行项目source control的过程中,有些文件不在source control之下,右键点击时,也找不到Undo, Commit命令 无法把他们签入进Source Contr ...

  3. C#Windows窗体界面设计_01_绘制三角函数_附强制类型转换

    binzhouweichao@163.com 今天开始学习C#windows窗体界面设计. 首先说一下类型转换. 参考http://www.csharpwin.com/csharpspace/6848 ...

  4. Codeforces Gym 100418B 暴力

    Sum of sequencesTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/v ...

  5. asp.net mvc控制器动作体返回ImageResult,可作验证码

    public ActionResult Img() { // 获取博客园空间顶部的banner图片 WebRequest req = WebRequest.Create("http://sp ...

  6. iOS开发技巧系列---详解KVC(我告诉你KVC的一切)

    KVC(Key-value coding)键值编码,单看这个名字可能不太好理解.其实翻译一下就很简单了,就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值.而不需 ...

  7. 免费的天气预报API--谷歌,雅虎,中央气象台

    Google Weather API 仅仅支持美国地区使用邮政编码进行查询,比如:  http://www.google.com/ig/api?hl=zh-cn&weather=94043  ...

  8. C++ _access和_waccess的使用方法

      C++ _access和_waccess的使用方法 概述 头文件:<io.h> 判断文件的访问权限 原型 int _access( const char *path,   int mo ...

  9. QNetworkAccessManager的异步与线程

    Qt版本5.1.1 以HTTP操作为例 Qt中的HTTP操作都是异步的. 内部通过线程实现 创建线程的时机在QNetworkReplyHttpImplPrivate::postRequest() vo ...

  10. Asp.Net 之 服务器端控件与客户端控件的区别

    服务器控件,即Asp.Net的控件,控制这些控件必须经过服务器处理,然后响应用户,代码在服务器端解释执行,生成根据用户的浏览器而定的html元素. 客户端控件,即普通Html控件,使用script控制 ...