美文网首页技术
EventBus 使用

EventBus 使用

作者: 射覆 | 来源:发表于2016-01-11 13:09 被阅读930次

EventBus 是一款针对 Android 端优化的 publish/subscribe 消息总线。

eventbus arch

主要目的是替代Intent, Handler,BroadCast 在 Fragment,Activity,Service,线程之间传递消息,优点是开销小,代码优雅。将发送者和接收者解耦。

基本用法

引入 eventbus:

compile 'de.greenrobot:eventbus:2.4.0'

定义事件:

public class MessageEvent { /* Additional fields if needed */ }

注册事件接收者:

eventBus.register(this);

发送事件:

eventBus.post(event)

接收消息并处理:

public void onEvent(MessageEvent event) {} 

注销事件接收:

eventBus.unregister(this);

最后,proguard 需要做一些额外处理:

# EventBus
-keepclassmembers class ** {
    public void onEvent*(**);
    void onEvent*(**);
}

基本概念

作为一个消息总线,有三个主要的元素:

  • Event:事件。可以是任意类型的对象
  • Subscriber:事件订阅者,接收特定的事件。在EventBus中,使用约定来指定事件订阅者以简化使用。即所有事件订阅都都是以onEvent开头的函数,具体来说,函数的名字是onEvent,onEventMainThread,onEventBackgroundThread,onEventAsync这四个,这个和ThreadMode有关
  • Publisher:事件发布者,用于通知 Subscriber 有事件发生。可以在任意线程任意位置发送事件,直接调用 eventBus.post(Object) 方法,可以自己实例化 EventBus 对象,但一般使用默认的单例就好了:EventBus.getDefault(), 根据 post 函数参数的类型,会自动调用订阅相应类型事件的函数。

指定处理线程

默认情况下,onEvent 方法会在 post(Event) 的方法的线程中执行,但是可能会 post(Event) 是一个非UI线程,而 onEvent 方法需要更新UI,需要在主线程运行。

public void onEventMainThread(MessageEvent event) {
    textField.setText(event.message);
}

因为每个事件订阅函数都是和一个 ThreadMode 相关联的,ThreadMode 指定了会调用的函数。有以下四个 ThreadMode:

  • PostThread:事件的处理在和事件的发送在相同的进程,所以事件处理时间不应太长,不然影响事件的发送线程,而这个线程可能是UI线程。对应的函数名是 onEvent。
  • MainThread: 事件的处理会在UI线程中执行。事件处理时间不能太长,这个不用说的,长了会ANR的,对应的函数名是onEventMainThread。
  • BackgroundThread:事件的处理会在一个后台线程中执行,对应的函数名是 onEventBackgroundThread,虽然名字是 BackgroundThread,事件处理是在后台线程,但事件处理时间还是不应该太长,因为如果发送事件的线程是后台线程,会直接执行事件,如果当前线程是 UI 线程,事件会被加到一个队列中,由一个线程依次处理这些事件,如果某个事件处理时间太长,会阻塞后面的事件的派发或处理。
  • Async:事件处理会在单独的线程中执行,主要用于在后台线程中执行耗时操作,每个事件会开启一个线程(有线程池),但最好限制线程的数目。

使用 Sticky Events

某些时候,我们并不希望发布出来的Event立即被消费掉,而是等到时机成熟。比如说,在一个详情页点赞之后,产生一个VoteEvent,VoteEvent并不立即被消费,而是等用户退出详情页回到商品列表之后,接收到该事件,然后刷新Adapter等。其实这就是之前我们用startActivityForResult和onActivityResult做的事情。

那么怎么用EventBus来模拟这样的情况呢?这就需要另外一个强大的机制,Sticky Event.

和普通的Event不同,当发布一个Sticky Event,需要使用postSticky方法:

EventBus.getDefault().postSticky(new VoteEvent(obj));

上面的代码发布了一个点赞的Sticky Event.

...
EventBus.getDefault().registerSticky(this);
...

public void onEventMainThread(VoteEvent event) {
    // TODO update adapter
}

EventBus 的 registerSticky 方法在每次执行的时候,都会去查询一次 Sticky Event,并调用响应的方法处理。

除了 registerSticky 方法来触发Sticky Event 之外,我们还可以通过 getStickyEvent 方法来获取响应的 Sticky Event 来进行处理。比如,我们可以在 onResume 方法里面检查 EventBus 里面是否有 VoteEvent 的Sticky Event,从而进行处理:

@Override
public void onResume() {
    super.onResume();
    VoteEvent voteEvent = EventBus.getDefault().getStickyEvent(VoteEvent.class);
}

3.0 beta 版本的变化

3.0 版本目前还在 beta 阶段,主要变化时使用注解代替基于惯例的 onEvent 方法,用法如下:

@Subscribe(threadMode = ThreadMode.MainThread)
public void onVoteEvent(VoteEvent event) {
}

进阶

想要探索更幽深的世界,就去看源码吧:

EventBus源码研读

相关文章

网友评论

    本文标题:EventBus 使用

    本文链接:https://www.haomeiwen.com/subject/ifwqkttx.html