EventBus介绍
转自:http://blog.csdn.net/huangyanan1989/article/details/10858695
场景描述
当一个Android应用功能越来越多的时候,保证应用的各个部分之间高效的通信将变得越来越困难。
在应用中的多个地方,控件经常需要根据某个状态来更新他们显示的内容。这种场景常见的解决方式就是定义一个接口,需要关注该事件的控件来实现这个接口。然后事件触发的地方来注册/取消注册这些对该事件感兴趣的控件。
例如,陌陌依赖手机位置信息来获取附近的用户,所以在位置更新管理器(MmLocationManager)中定义了一个接口来监听位置更新的事件(MmLocationListener):
1
2
3
|
interface MmLocationListener {
void onLocationChanged(Location location);
}
|
然后在应用的各个需要响应该事件的地方来实现上面的接口,然后在位置更新管理器(MmLocationManager)中注册/取消注册事件监听接口的实现类:
1
|
mLocationManager.get().register( this );
|
当不在需要监听的时候,取消注册
1
|
mLocationManager.get().unregister( this );
|
问题
上面的解决方案是没问题的,但是不是理想方案。每个控件实现这个接口,导致这些控件和位置管理器注册强耦合在一起。这还意味着,当单元测试的时候,您需要模拟(mocked)位置管理器来生成位置更新事件。
随着应用功能的增加,需要监听的事件越来越多,而越来越多的控件需要监听不同的事件,则导致越来越多的控件需要注册到各种事件管理器上:
1
2
3
4
5
6
|
// 代码开始变得无法控制…
mLocationManager.get().register( this );
userAuthenticator.get().register( this );
settingsManager.get().register( this );
syncManager.get().register( this );
configurationMonitor.get().register( this );
|
注意:上面的每个事件的注册,都要实现对应的时间更新接口。
注册和取消注册这些事件慢慢的会变得越来越难以管理。导致测试越来越困难,并将导致开发者的效率越来越低,同时在您的应用中越来越容易引入各种奇怪的Bug。
解决方案
为了找出该问题的优雅解决方案,从一个意想不到的的地方借鉴点经验 — Swing应用。 Event Bus模式 — 也被称为Message Bus或者发布者/订阅者(publisher/subscriber)模式 — 可以让两个组件相互通信,但是他们之间并不相互知晓。
和需要注册各个事件的监听器相比,一个组件现在只用在Event Bus上注册一次即可:
1
|
bus.register( this );
|
上面的注册告诉Event Bus我们现在希望接收各个事件的更新。 然后Bus检测该类中每个带有@Subscribe注解的函数,当相关的事件发生的时候就调用这些带有注解的函数。
上面示例中的位置监听功能,不用实现位置监听接口和里面的函数了,只需要提供一个带有@Subscribe注解的函数即可:
1
2
3
4
|
@Subscribe
public void locationChanged(LocationChangedEvent event) {
// TODO React to location change.
}
|
现在Event Bus会把所有的LocationChangedEvent 事件都发送给上面的函数。
现在 MmLocationManager 类不用注册监听器了,当位置改变的时候 只需要向Event Bus发布事件即可:
1
|
bus.post( new LocationChangedEvent( 37.892818 , - 121.772608 ));
|
这样 组件间相互解耦了,而单元测试也变得简单了。任何事件都可以发布给Event Bus,然后Event Bus会找到对该事件感兴趣的函数来调用。
注意:您也许已经发现该模式在Android上层也存在 — Intent系统就是这样设计的!
下面介绍两个Android系统的Event Bus模式类库。
Otto — Android系统的Event Bus类库
Otto是Square公司在他们应用中使用的Event Bus实现。从Guava中演变而来,并且专注于Android平台。
通过使用Otto,Square公司的应用组件间不紧密耦合了,单元测试也更加容易了。
您可以通过Otto项目的主页来了解更多内容或者查看Otto项目的源代码。
EventBus — Android系统的Event Bus类库
EventBus 是http://greenrobot.de 出品的另外一个Event Bus类库,功能稍微多一点。
EventBus使用起来和Otto差不多,分订阅、注册、发布、取消注册等步骤:
在订阅者类中实现各种事件的订阅函数
public void onEvent(AnyEventType event) {}
把该订阅类注册到Bus中
eventBus.register(this);
向Bus发布事件
eventBus.post(event);
不需要的时候 取消订阅事件
eventBus.unregister(this);
otto介绍
Otto 是Android系统的一个Event Bus模式类库。用来简化应用组件间的通信。关于Event Bus模式的详细情况,请参考这里。
Otto的使用是比较简单的,先到项目主页下载源码:https://github.com/square/otto
下载后的源码目录中包含一个library和sample目录, library目录是类库源代码;sample目录是示例代码。
主要使用com.squareup.otto.Bus类、@Produce、 @Subscribe 注解。
在组件的相关生命周期中通过Bus类的register 函数来注册,然后Bus类会扫描改类中带有@Produce和 @Subscribe 注解的函数。
@Subscribe 注解告诉Bus该函数订阅了一个事件,该事件的类型为该函数的参数类型;而@Produce注解告诉Bus该函数是一个事件产生者,产生的事件类型为该函数的返回值。
可以在Activity或者Fragment的onResume函数中注册监听器;在onPause函数中取消注册:
@Override protected void onResume() {super.onResume();// Register outselves so that we can provide the initial value.BusProvider.getInstance().register(this);}@Override protected void onPause() {super.onPause();// Always unregister when an object no longer should be on the bus.BusProvider.getInstance().unregister(this);}
对于在前面文章中介绍的场景,可以定义一个位置产生函数:
@Produce public LocationChangedEvent produceLocationEvent() {// Provide an initial value for location based on the last known position.return new LocationChangedEvent(lastLatitude, lastLongitude);}
该函数的@Produce注解告诉Bus该函数可以产生一个类型为LocationChangedEvent的事件,当有该类型的事件向Bus注册的时候, Bus会调用该函数获取初始值,并使用该值来调用订阅该事件的函数。
而对于需要订阅该事件的地方,通过@Subscribe注解来告诉Bus:
@Subscribe public void onLocationChanged(LocationChangedEvent event) {locationEvents.add(0, event.toString());if (adapter != null) {adapter.notifyDataSetChanged();}}
需要注意的是,不管是生产者还是订阅者都需要向Bus注册自己:
bus.register(this);
如果您认为在每个Activity或者Fragment的onResume和onPause函数中都需要调用bus.register(this)和bus.unregister(this)函数比较麻烦的话,可以通过一个Bus包装类来自动
完成注册的工作,然后在您的类中只需要继承基类,并调用函数getScopedBus().register(…) 来注册需要的对象即可。详细情况参考示例代码:https://gist.github.com/3057437
执行线程
Otto的事件调用默认是在主线程(应用的UI线程)中调用,
// 下面两种声明方式是一样的效果. Bus bus1 = new Bus(); Bus bus2 = new Bus(ThreadEnforcer.MAIN);
如果您不关注在那个线程中执行事件函数,则可以通过 ThreadEnforcer.ANY 参数来初始化Bus对象,
如果上面2个线程控制方式满足不了您的需求,您还可以通过实现ThreadEnforcer接口来定义自己的线程模型、
或者使用EventBus类库,我们将在下一篇文章中介绍EventBus和Otto的区别。
EventBus 使用介绍
上面的3种事件响应函数,应该能够很快的执行完,不然的话会阻塞各自的事件发布。
async:事件响应函数在另外一个异步线程中执行。该线程和发布线程、主线程相互独立。如果事件响应函数需要较长的时间来执行,则应该使用该模式,例如 网络访问等。需要注意的是,由于系统并行的限制,应该避免在同一时间触发大量的异步线程。 EventBus使用一个线程池来提高线程的效率。
3. EventBus支持 Sticky Event
有时候某个事件可能会用到多次,比如在前面介绍Event Bus模型一文的示例中,最新的位置更新信息,可能需要多次用到,真对这种情况,您可以把该事件发布为Sticky Event,然后,当需要查询该信息的时候,可以通过Bus的getStickyEvent(ClasseventType) 函数来查询最新发布的Event对象。
同一类型的事件只保存最新的Event对象。
注册和发布事件的函数分别为 registerSticky(…) 和 postSticky(Object event)
在项目主页上还有和Otto之间性能对比的表格,以及性能测试的源码。
EventBus介绍相关推荐
- EventBus介绍与使用
ps:虽然EventBus是Android中的一款开源框架,但是它确值得任何一个开发者学习 如果你学习过设计模式,那么你一直知道观察者模式.,既然能想到这个设计模式,那么就来看一个Android开源框 ...
- EventBus使用介绍
EventBus介绍 EventBus是一种用于Android的事件发布-订阅总线,由GreenRobot开发,它利用发布/订阅者者模式来对项目进行解耦,它简化了应用程序内各个组件之间进行通信的复杂度 ...
- Android消息传递之EventBus 3.0使用详解
前言: 前面两篇不仅学习了子线程与UI主线程之间的通信方式,也学习了如何实现组件之间通信,基于前面的知识我们今天来分析一下EventBus是如何管理事件总线的,EventBus到底是不是最佳方案?学习 ...
- EventBus使用总结和使用场景
一.EventBus介绍 EventBus是一个Android端优化的publish/subscribe消息总线,简化了应用程序内各组件间.组件与后台线程间的通信.传统的事件传递方式包括:Handle ...
- Android开源框架——事件总线 EventBus3.0讲解
开源项目地址 官网:https://github.com/greenrobot/EventBus 介绍 EventBus主要使用了观察者模式设计方案.主要替代Intent.Handler. Broad ...
- Android基础 EventBus3 0实用教程
作为一个Android开发者,我们在日常的开发中肯定会使用到EventBus,比如说当我们在做app的消息模块的时候,接收到后台推送的消息之后,为了方便用户查看,就需要把消息保存到本地,正常情况下在页 ...
- 双非同学,自学编程,毕业一年逆袭百度!
大家好,我是鱼皮,最近秋招快到了,我就想着给大家找一些优秀的程序员面经分享.希望可以帮助准备求职的同学更稳地上岸,同时帮助学编程的小伙伴们更好地明确学习路线和方法. 今天要分享的呢,是一位 双非非科班 ...
- eventbus使用_Android EventBus框架的使用介绍
EventBus 是Android和Java数据通信的一个简捷框架,在Android中,主要用于线程直接的通信以及Activity,Fragment等之间的数据交互等 官方介绍 简化组件之间的通信,解 ...
- EventBus设计与实现分析——特性介绍
EventBus是一个 发布/订阅 模式的消息总线库,它简化了应用程序内各组件间.组件与后台线程间的通信,解耦了事件的发送者和接收者,避免了复杂的.易于出错的依赖及生命周期问题,可以使我们的代码更加简 ...
最新文章
- [hdu5225][BC#40]Tom and permutation
- 用python画玫瑰花教程-使用Python画一朵玫瑰花
- python网课一般多少钱-排名前十的python零基础编程在线网课一对一费用多少钱
- eclipse插件egit安装使用
- [转]宝文!Apple Push Notification Service (APNS)原理与实现方案
- python 网页调试_使用Django 2.0构建Python Restful Web服务:七)在浏览器中浏览和调试restful接口...
- UITextView自定义placeholder功能:用一个label写了文字,然后当检测到长度不为0的时候就把label隐藏...
- 平稳时间序列分析:ARMA模型
- 基于netty框架的JTT808/JTT905/JTT1078协议客户端
- PYTHON判断回文素数
- ZZM区块链全球区块文化娱乐相结合的新型网站源码
- 高瓴投的澳斯康生物冲刺科创板:年营收4.5亿 丢掉与康希诺合作
- 【web前端】H5图片制作
- 「冰河技术」部分精华文章分类汇总,P8架构师都在看的技术文章!!
- 网络游戏运营策略分析
- 四则运算web版需求规格说明书
- 停车管理系统程序c语言,停车场管理系统C语言实现
- 关于NFV需要了解的知识
- 燕园思达刘有林董事长一行 参观考察延安高新技术产业开发区
- CAD入门图形和标注1