Android EventBus二三事

废话不少的前言

EventBus,也即事件总线。在wiki上有关于Event Monitor的一个说法:java

Event monitoring makes use of a logical bus to transport event occurrences from sources to subscribers, where event sources signal event occurrences to all event subscribers and event subscribers receive event occurrences.
事件监听器经过逻辑总线来将发生的事件从发生源传输到订阅者。事件发生源在事件发生的时候可以发出信号给全部订阅者,订阅者则可以接收到发生的事件。android

我的猜想事件总线这种说法源至于计算机内经常使用的几个总线结构【好比CPU总线,IO总线等】。他们有一个共同的特定就是负责传递某种 object 到指定的地方。好比数据总线负责的是CPU到RAM,地址总线负责的是RAM到RAM传递数据。git

这条词条的分类是在操做系统这个目录下,这也能够理解成是在操做系统较早地使用了这种模式。
在Java内置的包中也有一种EventBus,但它是基于接口的。Google在Guava中实现了一套本身的EventBus,Google实现的总线库更具可读性,由于它使用Annotion标记订阅者和生产者,方法名能够自定义,更具意义。github

Android中的EventBus

在这里先说说Android内置的两种跟EventBus相似的机制。IntentBroadcastReceiver
这二者均可以起到跟事件总线相似的效果。注册广播接收器和单纯发一个intent就能够唤起其余组件,提醒其余组件更新,这是很是方便的,同时也是下面提到的两个开源方案所作不到的。
但这种机制也有很差地方,它们内部的实现都须要 IPC,虽然Android的Binder使得IPC简单了点~~(仍是蛮复杂的吧)~~,但传递效率上会是个问题。若是本身彻底不须要IPC,下面说到的两个项目会更加适合。
在Android中彷佛就只有两个Eventbus的开源项目,Square的otto和GreenRobot的EventBus(如下称GEventBus)。ide

otto

otto是square开源的一个基于Guava的EventBus的项目。跟Guava同样,otto使用Annotion做为事件的标记,@Subscribe即事件的处理者,@Produce是基本事件的生产者。举个官方给的例子:函数

<!-- lang: java -->post

@Subscribe public void answerAvailable(AnswerAvailableEvent event) {  
    // TODO: React to the event somehow!  
}  
@Produce public AnswerAvailableEvent produceAnswer() {  
    return new AnswerAvailableEvent(this.lastAnswer);  
}  
// 订阅者和发布者均须要向同一个总线注册  
bus.register(this);

使用起来就是这么简单。订阅者向总线注册,若是此时存在一个生产者,那么这个生产者的方法会被调用以产生一个初始对象来初始化订阅者。另外,在总线接收到对应的事件以后,订阅者的方法就也会被调用。this

bus.post(new AnswerAvailableEvent(100));

post事件并不须要对象向总线注册。post事件后,若是存在事件的订阅者那么订阅者的方法就会被调用。若是不存在订阅者,那么事件会被包裹成DeadEvent重抛。(待作文章细说)。 默认状况下,otto只支持主线程的事件。好比下面代码所示,bus1和bus2是等价的。若是将策略设置为ANY,那么也能够在非主线程执行。只是不建议,这个库适合的场景也就只是在主线程而已,其余环境下会出现什么情况不作保证。google

Bus bus1 = new Bus();  
Bus bus2 = new Bus(ThreadEnforcer.MAIN);  
// Bus bus3 = new Bus(ThreadEnforcer.ANY);

小问题

要想在基类中注册事件要花点心思。(不能经过this来向bus注册事件,由于在子类中的方法调用super到父类方法时,this指的永远是子类)。要想在基类注册事件,基本上只能写一个成员变量,在变量内部注册方法。逻辑会略奇怪。另外,可能须要本身实现一个BusProviderurl

GEventBus

greenrobot的另外一个比较出名的开源项目(另一个是greenDAO)。一样是EventBus,但这个项目不是基于Annotion的。由于Android的Runtime Annotion处理起来效率实在是不高,尤为是在4.0以前。在4.0以后也不见得效率有多大提升
GEventBus使用的是字符串匹配,默认订阅者会调用带onEvent或者说是EventBus类里面的DEFAULT_METHOD_NAME做为前缀的方法。只有仔细跟踪代码以后,你才会发现它的几种线程模型是这么用的:

public void onEvent(SimpleEvent event) {};  
public void onEventBackgroundThread(SimpleEvent event) {};  
public void onEventMainThread(SimpleEvent event) {};  
public void onEventAysnc(SimpleEvent event) {};

其余操做跟otto相似。只是GEventBus不支持生产者方法。(题外话:我是看了otto的demo以后才知道GEventBus的通常用法= =)

问题

  1. 跟otto同样,若是用继承可能会存在问题。但具体的问题大概刚好相反,若是一个父类向总线注册了事件,在otto里面是只有子类注册了事件,但在GEventBus中会是子类和父类都注册了。若是父类中注册了总线,那么子类中必须实现一个onEvent*方法,不然程序就会崩掉。解决方案,也算有吧,本身实现了一个蛮挫的暂时性解决方案 issus98
  2. 默认方法是只能带一个参数的,若是传入多个参数,那么GEventBus会彻底忽略它,并且也不会报任何错误。这是个小细节,注意看文档的话大概也知道只能用一个参数,可是相较于otto会对参数不符合主动抛出一个RuntimeException,我始终以为GEventBus有问题。

我的见解

注意如下会有不少我的的喜爱致使的吐槽=_=

我的以为最纯正的是otto,即便GreenRobot的EventBus称它的效率比前者高出许多(有benchmark,因此算是事实)。可是一个开源项目,看的并不仅是效率问题吧。
在知乎上看到过一个问题:一个开源软件为什么成功。一个好的开源项目也是同理,其中有个答案提到的几点我很是赞同。

  1. 对新手友好。
    这点在EventBus上我彻底看不到。没有Demo,文档只是关于项目的一个简单介绍,还有吹嘘他们比起otto效率如何如何地高,功能多强大。
    另外还有一点,EventBus的文档极具误导性。对于TODO的feature,它居然摆在功能介绍的模块里,即便它前面加上了没有加粗的TODO。在Trinea的开源集合里面就把那些TODO的内容加到了EventBus的功能里面。 当初在看到它的效率如此地高,就决定选它了。但是没有demo,彻底不知道怎么入手。
  2. 及时接收反馈。
    EventBus上如今还有还有2012年的issues未关闭,并且不少都没有项目的人出来解答。不像otto,只要不是太弱智,基本上每一个issues都会有反馈。

在发现没有Demo以后,我研究过GEventBus的代码。逻辑是搞懂了,但也发觉了GEventBus的代码是如此地不友好,没有关键的注释,名字又表意不清。最最没法容忍的是,它将一堆函数标记为@depreated,即便如今只能用它们来作。这个Annotion是来这么用的吗?提供了新的替代接口再标记为废弃如何?或者你干脆设置成private好么。
看otto的代码是享受,虽然我只是稍微看了一下,没有深刻去研究。Square彷佛还为otto开发了IntellJ的plugin,能够快速地浏览全部的订阅者和生产者,这点也是GEventBus所不及的吧。
就我的喜爱而言,果真仍是选择otto,用annotion写起来仍是比较顺心的。不像GEventBus,居然要用那么长的名字才能做为事件回调。输入越多,越容易出错,这点不管是在用户体验仍是敲代码的时候都是同理。
我的拙见,欢迎交流>_< 22:09

博客连接:http://brainku.github.io/2014/09/20/something-about-eventbus/ 参考资料:

Android Annotion的bug 总线-百度百科 Guava EventBus EventBus otto

相关文章
相关标签/搜索