Guava: 事件总线EventBus
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中的几个问题?
- 事件定义:任意的对象即可;
- 事件处理器的注册:事件处理的方法,添加注解即可,然后事件处理器的对象注册到总线中,总线维护一个事件和事件处理器的关联关系,在内存中;
- 事件的处理过程:同步处理和异步处理,事件提交之后,事件队列维护在本地缓存,同步的方式直接当前线程去执行,异步的处理策略是在初始化事件总线的时候就搞了一个线程池出来,由线程池去异步执行;
- EventBus就开放了三个方法,register/post/unregister
- 为什么会有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的更多相关文章
- vue中央事件总线eventBus的简单理解和使用
公共事件总线eventBus的实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信.它是实现非父子组件通信的一种解决方案. 用法如下: 第一步:项目中创建一个js文件(我通 ...
- 【bird-java】分布式服务间的事件总线EventBus
什么是EventBusEventBus是对发布-订阅模式的一种实现.其以一种非常优雅的方式实现了组件间的解耦与通信,在Android开发.DDD等领域都有非常广泛的应用. 事件流大致如下: Produ ...
- Android事件总线EventBus详解
顾名思义,AndroidEventBus是一个Android平台的事件总线框架,它简化了Activity.Fragment.Service等组件之间的交互,很大程度上降低了它们之间的耦合,使我们的代码 ...
- 自己动手写事件总线(EventBus)
本文由云+社区发表 事件总线核心逻辑的实现. EventBus的作用 Android中存在各种通信场景,如Activity之间的跳转,Activity与Fragment以及其他组件之间的交互,以及在某 ...
- C# 事件总线 EventBus
1. 引言 事件总线这个概念对你来说可能很陌生,但提到观察者(发布-订阅)模式,你也许就很熟悉.事件总线是对发布-订阅模式的一种实现.它是一种集中式事件处理机制,允许不同的组件之间进行彼此通信而又不需 ...
- 事件总线EventBus
什么是事件总线管理? 将事件放到队列里,用于管理和分发: 保证应用的各个部分之间高效的通信及数据,事件分发: 模块间解耦: 什么是EventBus? EventBus是发布/订阅的事件总线.Event ...
- ASP.NET Core基于微软微服务eShopOnContainer事件总线EventBus的实现
这个EventBus的实现是基于微软微服务https://github.com/dotnet-architecture/eShopOnContainers项目的,我把它从项目中抽离出来,打包成nuge ...
- 事件总线 EventBus
661. .net中事件模型很优雅的实现了观察者模式,同时被大量的使用在各种框架中. [2016-04-30 10:52:42]662. Prism框架中实现了一个典型的EventAggregator ...
- 基于ASP.NET Core 5.0使用RabbitMQ消息队列实现事件总线(EventBus)
文章阅读请前先参考看一下 https://www.cnblogs.com/hudean/p/13858285.html 安装RabbitMQ消息队列软件与了解C#中如何使用RabbitMQ 和 htt ...
随机推荐
- Linux 系统监控和诊断工具:lsof
1.lsof 简介 lsof 是 Linux 下的一个非常实用的系统级的监控.诊断工具. 它的意思是 List Open Files,很容易你就记住了它是 “ls + of”的组合~ 它可以用来列出被 ...
- Java学习笔记(一):数据类型与变量
数据类型 Java中存在2种数据类型,下面我们来详解一下: 基本数据类型: 引用数据类型: 可以用一张表来记录: 基本数据类型 整型 byte:1个字节8位,取值范围为:[-128, 127],直接写 ...
- Unity3D中关于场景销毁时事件调用顺序的一点记录
先说一下我遇到的问题,我弄了一个对象池管理多个对象,对象池绑定在一个GameObject上,每个对象在OnBecameInvisible时会进行回收(即移出屏幕就回收),但是当场景切换或停止运行程序时 ...
- 存储过程[st_MES_RptInspectShipment]
USE [ChangHong_612]GO/****** Object: StoredProcedure [dbo].[st_MES_RptInspectShipment] Script Date: ...
- NHibernate - ICriteria 查询
http://blog.knowsky.com/213234.htm http://blog.chinaunix.net/uid-20463341-id-1673509.html http://www ...
- ADO.NET 快速入门(八):处理 Errors
除了 Try/Catch 和 Exceptions 以外,新的 ADO.NET 数据框架也允许在 DataSet 的每行数据添加错误信息.如果 Updates 或者其他操作失败,SqlDataAdap ...
- 关于.net中线程原子性的自我总结
首先来张图,一张 cpu的简图,仅从个人理解角度理解画的 大体 解释下这张图 这是 一张 i5的简图i5 大家都知道 是双核四线程,(超线程技术)l1,l2,l3是 1,2,3级缓存. Cpu工作:每 ...
- Cocos2D Study - Preparation & Installation
---------------------------------------------------------------------------------------------------- ...
- delphi TPopupMenu.Popup
procedure TPopupMenu.Popup(X, Y: Integer); 这个点是相对桌面的而不是窗体的 GetCursorPos是鼠标的位置 鼠标动这个点就不一样 v ...
- 向linux内核加入系统调用新老内核比較
2.6内核 1>改动linux-source-2.6.31/kernel/sys.c文件,在文件末尾加入系统响应函数.函数实现例如以下: asmlinkage int sys_mycall(in ...