继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

EventBus 3.0使用

闲筝听雨
关注TA
已关注
手记 14
粉丝 7
获赞 31

1、EventBus的基本使用

使用之前将EventBus添加到你的项目中,如下:

implementation 'org.greenrobot:eventbus:3.1.1'

第一步:定义事件
事件是常用Java bean对象,没有任何特定要求,如下:

package com.sample.retrofitdemo;

public class MessageEvent {
    private String message;
    
    public MessageEvent(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

第二步:准备订阅者
订阅者实现事件处理方法(也称为“订阅者方法”),这些方法将在发布事件时调用。这些是使用@Subscribe注释定义的。
请注意,使用EventBus 3时,可以随便命名方法名称(没有像EventBus 2中那样的命名约定)。

@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent me) {
    tv.setText(me.getMessage());
 }

用户也需要注册和注销EventBus。只有在订阅者注册时,他们才会收到活动。在Android中,在Activity和Fragment中,您通常应该根据其生命周期进行注册。对于大多数情况,onStart / onStop工作正常:

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}
 
@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

第三步:发布活动
从代码的任何部分发布事件。所有当前注册的与事件类型匹配的订阅者都将收到它。

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

2、线程模式

EventBus可以为您处理线程:事件可以发布在与发布线程不同的线程中。一个常见的用例是处理UI更改。在Android中,UI更改必须在UI(主)线程中完成。另一方面,网络或任何耗时的任务不得在主线程上运行。EventBus帮助您处理这些任务并与UI线程同步(无需深入研究线程转换,使用AsyncTask等)。
在EventBus中,您可以使用四个ThreadModes中的一个来定义将调用事件处理方法的线程。
ThreadMode:POSTING
如果订阅者在使用事件处理函数时候指定了这种线程模式,那么该事件是在哪个线程发布出来的,那么处理函数就会在这个线程中执行,也就是说发布事件和接收事件是在同一个线程。在这种线程模式下尽量避免做耗时操作,因为会阻塞事件的传递,很有可能引起ANR

    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onMessageEvent(MessageEvent me) {
        tv.setText(me.getMessage());
    }

ThreadMode:MAIN
如果线程模式是MAIN,那么无论事件是在什么线程发送出来的,该事件处理函数都会在UI线程中执行,可以用来更新UI,但是注意不要做耗时操作。

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent me) {
        tv.setText(me.getMessage());
    }

ThreadMode: BACKGROUND
这种线程模式意思是,如果事件是在UI线程中发布出来的,那么该事件处理函数就会在子线程中执行;如果事件是在子线程中发布的,那就还在这个线程中处理。在这种模式下是不能更新UI操作的

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessageEvent(MessageEvent me) {
        tv.setText(me.getMessage());
    }

ThreadMode: ASYNC
这种线程模式就是说,无论事件在哪个线程发布,该事件的处理函数都会在新建的子线程中执行,此事件处理函数中是不能进行UI操作的

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onMessageEvent(MessageEvent me) {
        tv.setText(me.getMessage());
    }

3、EventBus的配置

EventBus提供了很多配置,一般的情况下我们可以不用配置.但是,如果你有一些其他要求,比如控制日志在开发的时候输出,发布的时候不输出,在开发的时候错误崩溃,而发布的时候不崩溃…等情况。
EventBus提供了一个默认的实现,但不是单例。

    EventBus eventBus = new EventBus();
    //下面这一条的效果是完全一样的
    EventBus eventBus = EventBus.builder().build();
    //修改默认实现的配置,记住,必须在第一次EventBus.getDefault()之前配置,且只能设置一次。建议在application.onCreate()调用
    EventBus.builder().throwSubscriberException(BuildConfig.DEBUG).installDefaultEventBus();

4、粘性事件

EventBus除了普通事件也支持粘性事件,这个有点类似广播分类中的粘性广播。本身粘性广播用的就比较少,为了方便理解成订阅在发布事件之后,但同样可以收到事件。订阅/解除订阅和普通事件一样,但是处理订阅函数有所不同,需要注解中添加sticky = true

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

// UI updates must run on MainThread
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent event) {   
    textField.setText(event.message);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);    
    super.onStop();
}

发送粘性事件
EventBus.getDefault().postSticky(new MessageEvent(“Hello everyone!”));
手动获取和删除粘性事件
如您所见,最后一个粘性事件在注册时会自动传递给匹配的订阅者。但有时手动检查粘性事件可能更方便。此外,可能需要删除(消耗)粘性事件,以便它们不再被传递。例:

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
}

5、优先事项和事件取消

虽然EventBus的大多数用例不需要优先级,也不需要取消事件,但在某些特殊情况下它们可能会派上用场。例如,如果应用程序位于前台,则事件可能会触发某些UI逻辑,但如果应用程序当前对用户不可见,则会有不同的反应。
订户优先权
您可以通过在注册期间为订户提供优先级来更改事件传递的顺序。

@Subscribe(priority = 1);
public void onEvent(MessageEvent event) {
    ...
}

在同一传递线程(ThreadMode)中,较高优先级的订户将在优先级较低的其他订户之前接收事件。默认优先级为0。
注意:优先级不会影响具有不同ThreadModes的订阅者的传递顺序!
取消活动发送
您可以通过从订阅者的事件处理方法调用cancelEventDelivery (Object 事件) 来取消事件传递过程 。任何进一步的活动交付将被取消,后续订阅者将不会收到该活动。

// Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){
    // Process the event
    ...
    // Prevent delivery to other subscribers
    EventBus.getDefault().cancelEventDelivery(event) ;
}

事件通常由优先级较高的订户取消。取消仅限于在发布线程(运行事件处理方法 ThreadMode .PostThread

6、订阅者索引

订户索引是EventBus 3的新功能。它是一种可选的优化,可加快初始订户注册。

可以使用EventBus批注处理器在构建期间创建订户索引。虽然不需要使用索引,但建议在Android上获得最佳性能。

指数先决条件
请注意,只能为订阅者和事件类公开索引@Subscriber方法。此外,由于Java注释处理本身的技术限制,@ Subscribe注释在匿名类中无法识别。

当EventBus无法使用索引时,它将在运行时自动回退到反射。因此它仍然可以工作,只是有点慢。

如何生成索引 使用annotationProcessor
如果您没有使用Android Gradle Plugin 2.2.0或更高版本,请使用android-apt配置。

要启用索引生成,您需要使用annotationProcessor 属性将EventBus批注处理器添加到构建中 。还要设置参数 eventBusIndex以指定要生成的索引的完全限定类。例如,将以下部分添加到Gradle构建脚本中:

android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ]
            }
        }
    }
}

dependencies {
    implementation 'org.greenrobot:eventbus:3.1.1'
    annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}

用kapt
如果要在Kotlin代码中使用EventBus,则需要使用 kapt 而不是 annotationProcessor :

apply plugin: 'kotlin-kapt' // ensure kapt plugin is applied

dependencies {
    implementation 'org.greenrobot:eventbus:3.1.1'
    kapt 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}

kapt {
    arguments {
        arg('eventBusIndex', 'com.example.myapp.MyEventBusIndex')
    }
}

使用android-apt
如果上述方法不适合您,可以使用android-apt Gradle插件将EventBus注释处理器添加到您的构建中。将以下部分添加到Gradle构建脚本:

buildscript {
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

apply plugin: 'com.neenbedankt.android-apt'

dependencies {
    compile 'org.greenrobot:eventbus:3.1.1'
    apt 'org.greenrobot:eventbus-annotation-processor:3.1.1'
}

apt {
    arguments {
        eventBusIndex "com.example.myapp.MyEventBusIndex"
    }
}

如何使用索引
成功构建项目后,将为您生成使用eventBusIndex指定的类 。然后在设置EventBus时将其传递给它:

EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();

或者,如果您想在整个应用中使用默认实例:

EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();

索引您的库
您可以将相同的原则应用于作为库的一部分的代码(而不是最终的应用程序)。这样,您可以拥有多个索引类,您可以在EventBus设置期间添加这些索引类,例如:

EventBus eventBus = EventBus.builder()
    .addIndex(new MyEventBusAppIndex())
    .addIndex(new MyEventBusLibIndex()).build();

最好实在Application启动的时候就调用这行代码保证之后所有的EventBus都默认使用了加速模式

7、EventBus的混淆

proguard-rules.pro文件中配置混淆

-keepattributes *Annotation*
-keepclassmembers class * {
    @org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
 
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
    (java.lang.Throwable);
}

8、异步执行器(AsyncExecutor)

AsyncExecutor就像一个线程池,但有失败(异常)处理。失败是抛出异常,AsyncExecutor会将这些异常包装在一个自动发布的事件中。

免责声明:AsyncExecutor是一个非核心实用程序类。它可能会为后台线程中的错误处理节省一些代码,但它不是核心EventBus类。

通常,您调用 AsyncExecutor 。create ()创建一个实例并将其保留在Application范围内。然后执行一些操作,实现 RunnableEx接口并将其传递给AsyncExecutor的execute方法。与Runnable不同 , RunnableEx可能会抛出异常。

如果 RunnableEx实现抛出异常,它将被捕获并包装到ThrowableFailureEvent中,该ThrowableFailureEvent将被发布。

执行示例:

AsyncExecutor.create().execute(
    new AsyncExecutor.RunnableEx() {
        @Override
        public void run() throws LoginException {
            // No need to catch any Exception (here: LoginException)
            remote.login();
            EventBus.getDefault().postSticky(new LoggedInEvent());
        }
    }
);

接收部分的示例:

@Subscribe(threadMode = ThreadMode.MAIN)
public void handleLoginEvent(LoggedInEvent event) {
    // do something
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void handleFailureEvent(ThrowableFailureEvent event) {
    // do something
}

AsyncExecutor Builder
如果要自定义AsyncExecutor实例,请调用静态方法 AsyncExecutor 。builder ()。它将返回一个构建器,该构建器允许您自定义EventBus实例,线程池和失败事件的类。

另一个自定义选项是执行范围,它为失败事件提供上下文信息。例如,失败事件可能仅与特定的Activity实例或类相关。

如果您的自定义失败事件类实现HasExecutionScope接口,AsyncExecutor将自动设置执行范围。像这样,您的订阅者可以查询失败事件的执行范围并根据它做出反应。

参考文献:EventBus官网文档

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP