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. HDU 5620 KK's Steel (斐波那契序列)

    KK's Steel 题目链接: http://acm.hust.edu.cn/vjudge/contest/121332#problem/J Description Our lovely KK ha ...

  2. codeforces 630B Moore's Law

    B. Moore's Law time limit per test 0.5 seconds memory limit per test 64 megabytes input standard inp ...

  3. 最新的支持DELPHI XE6的开发框架

    支持负载均衡集群的中间件 主界面 插件管理 角色与权限 用户与权限

  4. App启动加载广告页面思路

    需求 很多app(如淘宝.美团等)在启动图加载完毕后,还会显示几秒的广告,一般都有个跳过按钮可以跳过这个广告,有的app在点击广告页之后还会进入一个广告页面,点击返回进入首页.今天我们就来开发一个广告 ...

  5. << 移位运算

    /** * The maximum capacity, used if a higher value is implicitly specified * by either of the constr ...

  6. .Net 揭密--JIT怎样运行你的代码

    方法调用: 第一部分 (普通调用) 译者:我们都知道.NET托管代码如C#.VB.NET写成的代码,都是先被编译成中间语言(IL,Intermediate Language,在运行时,再由即时编译器( ...

  7. 学习微软中间语言(MSIL)的绝佳工具 Dotnet IL Editor 推荐

    Dotnet IL Editor是一款.NET平台反编译工具,可以反编译.NET程序集文件为IL代码,并且可以执行,调试反编译后生成的IL代码.它的设计出发点比较直观,新建一个项目,添加程序集文件,设 ...

  8. 多线程和Boost::Asio

    线程安全 一般的,高并发使用不同的对象是安全的,在高并发中使用单一的对象是不安全的,io_service类型提供了单对象高并发的强安全保证. 线程池 多线程可能调用io_service::run()来 ...

  9. Laravel入门笔记

    Laravel 是一款简洁,优雅的一款框架,可以说是入门TP后的第二款可以选择的框架. 目录部分: app -> 自己写的代码 http -> Controller -> 控制器 b ...

  10. 在 C# 中加载自己编写的动态链接库

    一.发生的背景    在开发新项目中使用了新的语言开发 C# 和新的技术方案 WEB Service,但是在新项目中,一些旧的模块需要继续使用,一般是采用 C 或 C++ 或 Delphi 编写的,如 ...