[Android]【安卓】EventBus3.0简介

[Android]【安卓】EventBus3.0简介

本篇博客已收录到我的安卓开发小结中——点击【安卓开发小结】

参考资料:Android开源库 EventBus 用法详解<译文>

一、为什么使用EventBus?

  • 跨线程解耦通信:EventBus是一个使用发布者/订阅者模式 并且低耦合的Android开源库。EventBus只需几行代码即可实现中央通信解耦类,简化代码,删除依赖关系,加快应用程序开发速度。
  • 高性能:Android系统上,性能尤为重要。EventBus被针对性的做了大量的分析和优化;EventBus可能是这类开源库中速度最快的解决方案。基于API的便捷注解(不牺牲性能),只需将@Subscribe注解添加订阅方法即可。由于构建的时候花费了时间来建立注解的索引,所以EventBus不需要在应用程序的运行时间执行注释反射,注解反射的方式在Android上相当慢。
  • 高可靠性:EventBus是最常用的Android库之一,在实践中已通过100,000,000次安装的应用程序证明,成千上万的应用程序使用EventBus,其中不乏非常受欢迎的应用程序。我们认为差不多有十亿应用程序使用EventBus。
  • 易用性:EventBus是一个微小的库,jar包小于50K,具有超级容易学习的API。可以从代码中的任何地方立即使用默认的EventBus实例。

二、如何使用EventBus?

1、添加EventBus到工程

有三种方式:
a、在gradle中依赖

compile 'org.greenrobot:eventbus:3.0.0'

b、在maven中配置

<dependency>
    <groupId>org.greenrobot</groupId>
    <artifactId>eventbus</artifactId>
    <version>3.0.0</version>
</dependency>

c、直接只用jar包
jar

2、定义事件

事件是纯Java对象,没有其他的特殊要求

public class MessageEvent {
    public final String message;
    public MessageEvent(String message) {
        this.message = message;
    }
}
3、准备订阅者

订阅者需要实现在事件发布时将被调用的事件处理方法(也称为“订阅方法”)。这些订阅方法将用@Subscribe注释定义。 注意,使用EventBus3可以自由选择方法名(没有像EventBus2中的命名约定。

// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
    Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}

// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
    doSomethingWith(event);
}

订阅者还需要向总线注册和注销。 只有订阅者注册后,他们才会收到事件。 在Android的在活动和片段中,通常应该根据其生命周期进行注册。 对于大多数情况下在onStart中注册,在onStop中销毁就OK了。

    @Override
    protected void onStart() {
        EventBus.getDefault().register(this);
        super.onStart();
    }

    @Override
    protected void onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }
4、发布事件

在代码的任意地方发布事件,所有与当前事件匹配且注册过的订阅者都将会收到事件。(匹配是指订阅者的订阅方法中的类和发布事件中的事件类一致,即方法签名相同)

EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

三、补充说明

1、原理简介

这里写图片描述

在代码的任何地方,通过EventBus.getDefault().post(new yourEvent());方法即可发布一个事件,接受者只要向总线注册了事件,即可接收到发布的事件。

2、线程问题

EventBus可以为你处理线程:事件可以发布到不同于发布线程的线程中。
一个普遍的场景就是处理UI的变化。在Android系统中,UI更改必须在UI(主)线程中完成。另一方面,网络或者任何耗时的任务,都不允许在主线程中执行。EventBus帮助你处理这些任务并且与UI线程同步(无需深入了解线程转换,使用AsyncTask等)。
在EventBus中,你可以通过使用四个ThreadMode中的一个来定义将调用事件处理方法的线程。

  • ThreadMode: POSTING
    订阅者将会在事件发布的线程中被调用。这是默认模式。事件的传递是同步完成的,一旦事件发布完成,所有的订阅者都将会被调用。由于完全避免了线程切换,这种模式的开销是最小的。所以,针对那些不需要主线程并且能在很短时间内完成的简单任务,我们推荐使用这种模式。这种模式下的事件处理方法必须快速返回,避免阻塞发布事件的线程,因为这个线程有可能是主线程,例如:
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
    log(event.message);
}
  • ThreadMode: MAIN
    订阅者将在Android的主线程(有时称为UI线程)中调用。 如果发布线程是主线程,则将直接调用事件处理方法(与ThreadMode.POSTING描述的同步)。 使用此模式的事件处理程序必须快速返回,以避免阻塞主线程,例如:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
textField.setText(event.message);
}
  • ThreadMode: BACKGROUND
    订阅者将在后台线程中调用。 如果发布线程不是主线程,事件处理程序方法将直接在发布线程中调用。 如果发布线程是主线程,EventBus使用单个后台线程来按顺序传递所有事件。 使用此模式的事件处理方法应尽快返回以避免阻塞后台线程,
    例如:
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
    saveToDisk(event.message);
}
  • ThreadMode: ASYNC
    事件处理方法在单独的线程中调用。 这个线程总是独立于发布线程和主线程。 这种模式下,发布事件不会等待事件处理方法的执行结果。 如果事件处理方法的执行需要一些时间,则应该使用此模式,如网络访问。 避免同时触发大量长时间运行的异步处理方法以限制并发线程的数量。 EventBus使用线程池来有效地重用已完成任务的线程,例如:
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
    backend.send(event.message);
}
3、优先级和事件取消
  • 订阅者优先级
    你可以通过在注册期间为订阅者提供优先级来更改事件传递的顺序。在相同的传递线程(ThreadMode)中,较高优先级的订阅者将在其他优先级较低的订阅者之前接收事件。 默认优先级为0。(注意:优先级不影响不同线程模式的订阅者之间的传递顺序)
@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
    ...
}
  • 事件取消
    你可以通过从订阅者的事件处理方法调用cancelEventDelivery(Object event)来取消事件传递过程。 任何其他活动传送将被取消,后续订阅者将不会收到活动。事件通常由更高优先级的订阅者取消。
    取消仅限于在发布线程(ThreadMode.PostThread)中运行的事件处理方法。
// Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){
    // Process the event
    ...
    // Prevent delivery to other subscribers
    EventBus.getDefault().cancelEventDelivery(event) ;
}
4、粘性事件

一些事件携带在事件发布之后感兴趣的信息。 例如,事件表示某些初始化完成。 或者如果您有一些传感器或位置数据,并且想要保持最近的值。 而不是实现自己的缓存,你可以使用粘性事件。 所以EventBus保持内存中某个类型的最后一个粘性事件。 然后粘性事件可以传递给订阅者或明确地查询。 因此,您不需要任何特殊的逻辑来考虑已有的数据。
示例:
下面表示一个发布了一段时间的粘性事件:

EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));

现在一个新的活动开始。 在注册期间,所有粘性订阅者方法将立即获得先前发布的粘性事件:

@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {   
    textField.setText(event.message);
}

手动获取和删除粘性事件
如你所见,最后一个粘性事件在注册时自动传递给匹配的订阅者。 但有时手动检查粘性事件可能会更方便。 另外,可能需要移除(消费)粘性事件才能使得它们不再被递送。 例:

MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
    // "Consume" the sticky event
    EventBus.getDefault().removeStickyEvent(stickyEvent);
    // Now do something with it
}

方法removeStickyEvent是重载的:当你传入类时,它将返回先前持有的粘性事件。 使用这个变化,我们可以改进前面的例子:

MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
// Better check that an event was actually posted before
if(stickyEvent != null) {
    // Now do something with it
}

猜你喜欢

转载自blog.csdn.net/Hystudio_lzu/article/details/80167122