EventBus3.0使用详解---参考官网

EventBus主要角色:

·         Event传递的事件对象

·         Subscriber  事件的订阅者 

·         Publisher  事件的发布者

·         ThreadMode定义函数在何种线程中执行

一、EventBus使用步骤:

1.定义事件

public class MessageEvent{

    publicfinal String message;

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

}

2.准备订阅者

订阅的实现在发送消息EventBus3.0之前是通过调用Subscriber 方法来发送,但是3.0之后是通过@Subscribe注解来说实现的

// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEventevent) {

    Toast.makeText(getActivity(),event.message, Toast.LENGTH_SHORT).show();

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

    doSomethingWith(event);

}

需要根据Activitys和Fragments的生命周期的onStart/onStop方法中进行注册和注销 订阅者还需要在总线上注册和注销,只有在用户注册的时候,才可以接收到事件。

@Override
public void onStart() {

    super.onStart();
    EventBus.getDefault().register(this);

}

@Override
public voidonStop() {

    EventBus.getDefault().unregister(this);
    super.onStop();

}

3.发送事件

可以在任意的地方发送事件,所有相匹配的事件类型都可以接收到它

EventBus.getDefault().post(newMessageEvent("Hello everyone!"));

二、EventBus四种发送模式

ThreadMode:POSTING 和发布者处于同一线程

      默认情况下订阅(Subscribe)和发送(Post)将会在同一个Thread中进行,事件(Event)的交付是同步的,一旦发布完成所有的订阅者(Subscribers)都将被调用,此模式下可以完全的避免线程(Thread)的转换,它占用的内存开销最少,因为它在主线程以外执行的时间非常短,在完成一些简单的任务是推荐使用这种模式。此种模式有可能是在主线程中执行的,事件处理完应该讯速的释放,免阻塞线程。

// Called in the same thread (default)
// ThreadMode is optional here
@Subscribe(threadMode = ThreadMode.POSTING)

public voidonMessage(MessageEventevent) {

    log(event.message);

}


ThreadMode:MAINAndroid主线程中 

       订阅者(Subscribers) 将会在Android 的主线程中被调用,如果发送(POST)也在主线程,事件的处理将会被立即执行(类似于ThreadMode.POSTING模式中的描述),同样事件处理完应该立即返回,以免阻塞线程

// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {

    textField.setText(event.message);

}


ThreadMode:BACKGROUD后台线程 

     订阅者将会在后台线程中调用,如果发送的线程是主线程,事件的处理将会被立即执行。在主线程中,EventBus使用一个单一的后台线程,事件将会按照顺序进行交付。同样事件处理完毕应立即返回,以免阻塞线程

// Called in the background thread
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEventevent){

    saveToDisk(event.message);

}

ThreadMode:ASYNC 异步线程

       事件的处理将在单独的线程中进行调用。独立于发送线程和主线程之外。使用此模式,发布事件将不会等待其处理,并且此模式可以执行耗时的操作,例如:访问网络。通过限制线程的数量,大量的长时间的异步处理,防止多线程的并发。

EventBus复用已完成的异步处理使用线程池来管理事件的。

// Called in a separate thread
@Subscribe(threadMode = ThreadMode.ASYNC)
public voidonMessage(MessageEventevent){

    backend.send(event.message);

}

三、EventBus配置 

EventBus使用EventBusBuilder类来进行管理,例如:通过构建者来保持订阅和发送

EventBus eventBus = EventBus.builder()
    .logNoSubscriberMessages(false)
    .sendNoSubscriberEvent(false)
    .build();
 订阅者需要抛出异常的例子

EventBuseventBus=EventBus.builder().throwSubscriberException(true).build(); 

注意:默认情况下,订阅者捕获一个SubscriberExceptionEvent可以不用处理

下面这个链接是EventBusBuilder的API

http://greenrobot.org/files/eventbus/javadoc/3.0/org/greenrobot/eventbus/EventBusBuilder.html

配置默认的EventBus实例

使用EventBus.getDefault可以简单方便获取EventBus的实例 

EventBusBuilder 调用installDefaultEventBus也可得到默认的实例

EventBus可以通过配置来抛异常,例如在DEBUG下抛出异常

EventBus
	.builder()
	.throwSubscriberException(BuildConfig.DEBUG)
	.installDefaultEventBus();

注意:上面的操作只能用在EventBus默认实例第一次被使用之前,然后才可以调用installDefaultEventBus()来抛异常。这样设计是为了保证APP的一致性。

 

四、Sticky Events

 解释:什么是Sticky事件?Sticky的意思是粘性的,Android开发中,Sticky事件只指事件消费者在事件发布之后才开始注册事件也能接收到该事件的特殊类型。比如StickyBroadcast,即粘性广播。正常情况下如果发送者发送了某个广播,而接收者在这个广播发送后才注册自己的Receiver,这是接收者无法接收到刚才的广播,所以Android引入了StickyBroadcast,在广播发送结束后会保存刚刚发送的发送到额广播(Intent),这样当接受者注册完Receiver后就可以接收刚才已经发布的广播。这就使得我们可以预先处理一些事件,让有消费者时再把这些事件投递给消费者。

       AndroidEventbus也提供了这样的功能,有所不同的时AndroidEvenBus会储存所有的Sticky事件,如果某个事件在不需要在储存则需要手动进行移除。用户通过Sticky形式发布事件,消费者也需要通过Sticky的形式进行注册,当然这种注册除了可以接收Sticky事件之外和常规的注册功能一样的,其他类型的事件也会被正常处理。

官方描述:

Some events carry information that is ofinterest after the event is posted. For example, an event signals that someinitialization is complete. Or if you have some sensor or location data and youwant to hold on the most recent values. Instead of implementing your owncaching, you can use sticky events. So EventBus keeps the last sticky event ofa certain type in memory. Then the sticky event can be delivered to subscribersor queried explicitly. Thus, you don’t need any special logic to consideralready available data.

翻译:有些事件会在事件发布之后带来消息,比如,一个事件在初始化的时候就已经是存在的。或者已经有一些传感器和位置信息的数据,但是又想获取最新的值。你可以使用StickyEvent替代,而不是自己实现高速缓存。所以EventBus在内存中保留了最后一个特定类型的粘性事件。然后就可以将粘性事件发送给订阅者,或者显示查询。因此,不需要对我们已有的数据做特殊的逻辑来实现。

Sticky Example

比方说,一段时间以前发布了一个粘性事件。

EventBus
    .getDefault()
    .postSticky(newMessageEvent("Hello everyone!"));
 
 

现在启动一个Activity。在此期间所以粘性用户将会立即得到先发发送的粘性事件

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

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

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

手动移除SickyEvent

正如所见, 当订阅者注册的时候最后一个粘性事件会自动匹配订阅者。但是有时需要我们手动的去检查粘性事件。有时候为了避免粘性事件的再次传递我们通常需要remove(消费)这个事件。

MessageEventstickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
// Better check that an event wasactually posted before
if(stickyEvent!=null) {

    // "Consume"the sticky event
    EventBus.getDefault().removeStickyEvent(stickyEvent);

    // Now dosomething with it

}

这个removeStickyEvent是重载方法,当你使用到这个类的时候,返回值是先前的粘性事件。利用这种变化我们可以改变刚才的例子


虽然我们大多是情况下使用EventBus不需要优先级和事件的取消,但是在某些特殊的情况下我们还是会用到。比如:我们的app处于前台,可能就会触发一些UI的逻辑,但是当其不可见的时候则会有不同的情况出现。
优先级和事件的取消

MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);

// Better check that an event was actually posted before
if(stickyEvent!=null) {

    // Now do something with it

}

用户优先级

为了改变事件的交付循序,这时候就需要给事件一个优先级来达到目的。

注意:优先级不会影响不同的线程模式(即ThreadMode中)的执行顺序。在要交付事件的线程内(ThreadMode中)高优先级先于低优先执行。默认的优先级为0。

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

 }

取消事件的交付

我们可以通过cancelEventDelivery(Object event)这个函数来取消用户事件处理。所有订阅的事件都将被取消,后续的订阅也将不会再接收到该事件。

// Calledin the same thread (default)
@Subscribe
public void onEvent(MessageEventevent){

    // Process the event
    ...

    //Prevent delivery to other subscribers
    EventBus.getDefault().cancelEventDelivery(event) ;

}

事件通常都是被高优先级的订阅者取消,取消仅限于在发布的线程中(ThreadMode.PostThread)正在运行的事件中处理

五、

订阅者索引

订阅者索引是EventBus3.0的新特性。这是一种可选择的可优化的,能够给订阅者带来更高的速度。

EventBus注解器在编译期就创建了订阅者索引,虽然EventBus不是必须使用索引,但是推荐使用Index以获得更好的性能。

索引的使用条件

注意:只有在@Subscriber 方法中才可以使用索引,并且要求订阅者和Event所在的类是public修饰的时候 ,还有就是@Subscriber注解器不能再匿名内部类中使用。当我们不使用EventBus的索引进行事件处理时,也能够正常运行,但是由于运行时使用了反射机制,所以性能会稍微低点。

如何生成索引?注解处理器(AnnotationProcessor)的使用

要求使用Gradle插件是2.2.0以上的版本,并且要在build.gradle配置annotationProcessor。还需要在使用eventBusIndex指定到你要生成Index的类中

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

            }
        }
    }
}

dependencies {

    compile 'org.greenrobot:eventbus:3.0.0'
	annotationProcessor'org.greenrobot:eventbus-annotation-processor:3.0.1'

}

使用kapt

 EnevtBus也开放了对Kotlin的支持,如果要使用Kotlin就要在annotationProcessor中配置kapt就行了。

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

dependencies {
    compile 'org.greenrobot:eventbus:3.0.0'
    kapt'org.greenrobot:eventbus-annotation-processor:3.0.1'
}

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

Android中要在Android-apt插件中配置EventBusAnnotationProcessorAndroid中apt的使用

buildscript {

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


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

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

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

索引的使用

配置好上面的操作之后build一下工程,然后就会自动生成EventBusIndex的业务Bean,生成以后我们就可以对索引进行操作了

EventBus eventBus=EventBus.builder().addIndex(newMyEventBusIndex()).build();

也可以使用EventBus默认的实例进行操作

EventBus.builder().addIndex(newMyEventBusIndex()).installDefaultEventBus();

// Now the default instance uses the givenindex. Use it like this:

EventBus eventBus =EventBus.getDefault();

当我们在使用的时候会有多个场景需要使用到Index,而这些场景会保存在我们的library中。使用以下方法满足我们的要求

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

六、EventBus混淆

由于代码混淆会改变方法名类名,所以会导致EventBus不能被使用

-keepattributes *Annotation*

-keepclassmembers class ** {

    @org.greenrobot.eventbus.Subscribe <methods>;

}

-keep enum org.greenrobot.eventbus.ThreadMode { *; }

# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {

    <init>(java.lang.Throwable);

}

七、异步执行注意:无论是不是使用Index都需要在混淆时做上面的操作

异步执行像是一个带有失败处理的线程池。AsyncExecutor会将异常封装到一个事件中,然后自动发布。

声明:AsyncExecutor会在后台线程中处理一些异常,但是他不是EventBus主要的类。

使用的时候我们需要AsyncExecutor。Create()来创建其实例并保存。然后实现RunnableEx接口,传递给AsyncExecutor的执行方法。于Runnable不同的时RunnableEx可能会抛出一个异常。如果RunnableEx抛出一个异常,就会被封装进ThrowableFailureEvent中进行发布。

示例如下:

AsyncExecutor.create().execute(

    new AsyncExecutor.RunnableEx() {

        @Override
        publicvoid run() throwsLoginException{

            // No need to catch any Exception (here:LoginException)
            remote.login();
            EventBus.getDefault().postSticky(new LoggedInEvent());

        }
    }
);

接收部分:

@Subscribe(threadMode=ThreadMode.MAIN)
public void handleLoginEvent(LoggedInEventevent) {

    // dosomething

}

@Subscribe(threadMode=ThreadMode.MAIN)
public void handleFailureEvent(ThrowableFailureEventevent) {

    // dosomething

}

八、AsyncExecutor Builder

调用AsyncExecutor.builder这个静态方法可以自定义AsyncExecutor的实例

原文如下:

If youwant to customize your AsyncExecutor instance, call the static method AsyncExecutor.builder(). It willreturn a builder which lets you customize the EventBusinstance, the thread pool, and the class of the failure event.

Anothercustomization option is the execution scope, which givesfailure events context information. Forexample, a failure event may be relevant only to a specific Activity instanceor class.

If yourcustom failure event class implements the HasExecutionScope interface,AsyncExecutor will set the execution scope automatically. Like this, yoursubscriber can query the failure event for its execution scope and reactdepending on it.

后记:第一次写博客哈!写的不好,可以喷不可以骂人哈,咱们的口号是能比比尽量不动手,希望大家多给点意见最后脑补一下我这也是为了自己学习,不是为了出名哈

最后一个官网的飞机票哈!!!

http://greenrobot.org/eventbus/documentation/how-to-get-started/


猜你喜欢

转载自blog.csdn.net/huangruqi888/article/details/76178972