美文网首页
EventBus 3.X 的使用

EventBus 3.X 的使用

作者: changchengfeng | 来源:发表于2018-05-12 12:13 被阅读218次

    这篇文章主要记录一下EventBus的使用,详情EventBus官方文档

    1. 概念

    EventBus能够简化各组件间的通信,让我们的代码书写变得简单,能有效的分离事件发送方和接收方(也就是解耦的意思),能避免复杂和容易出错的依赖性和生命周期问题。

    • 事件(Event):又可称为消息,本文中统一用事件表示。其实就是一个POJO对象
      事件分为一般事件和 Sticky 事件,相对于一般事件,Sticky 事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型事件,依然能收到该类型事件最近一个 Sticky 事件。

    • 订阅者(Subscriber):订阅某种事件类型的对象。当有发布者发布这类事件后,EventBus 会执行订阅者的 @Subscribe注解标记的方法,叫做事件响应。订阅者通过 register 接口订阅某个事件类型,unregister 接口退订。订阅者存在优先级,优先级高的订阅者可以取消事件继续向优先级低的订阅者分发(但是取消事件的线程必须和发布事件的线程一致),默认所有订阅者优先级都为 0。

    • 发布者(Publisher):发布某事件的对象,通过 post 接口发布事件。

    2. 简单使用

    2.1. 添加EventBus库
    api 'org.greenrobot:eventbus:3.1.1'
    
    2.2. 新建一个POJO对象代表一个事件(Event)
    public class MessageEvent {
    
        public final String message;
    
        public MessageEvent(String message) {
            this.message = message;
        }
    }
    
    2.3. 在生命周期里面注册和取消注册
    @Override
    public void onStart() {
        super.onStart();
        EventBus.getDefault().register(this);
    }
     
    @Override
    public void onStop() {
        EventBus.getDefault().unregister(this);
        super.onStop();
    }
    
    2.4. 订阅者处理事件
    // 当 MessageEvent 事件被发布这个方法会被调用(在主线程中显示一个 Toast)
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {
        Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
    }
    
    
    2.5. 发布事件

    发布事件的类和订阅者的类不相同时,两个类不直接引用就可以进行通信.

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

    3. 扩展

    3.1. ThreadMode (线程模式)

    订阅者响应事件的方法是通过 @Subscribe 注解标注的,其中有个 ThreadMode 属性可以进行控制响应事件方法的执行线程,一共有 5 种线程模式可以进行配置

    • ThreadMode: POSTING (默认)

    订阅者(Subscriber)发布者(Publisher) post 事件相同的线程中执行响应事件的方法,若 发布者(Publisher) post 的线程是主线程,则 订阅者(Subscriber) 处理事件的线程也在主线程中执行,若 发布者(Publisher) post 事件的线程是子线程,则 订阅者(Subscriber) 处理消息事件的线程也是在子线程中执行.

    // Called in the same thread (default)
    // ThreadMode is optional here
    @Subscribe(threadMode = ThreadMode.POSTING)
    public void onMessage(MessageEvent event) {
        log(event.message);
    }
    
    • ThreadMode: MAIN

    订阅者(Subscriber) 在主线程中执行响应事件的方法,如果 发布者(Publisher) post 事件是主线程,则直接调用响应事件的方法,如果 post 的是子线程,则加入到主线程的消息循环队列中执行响应事件的方法,

    // Called in Android UI's main thread
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessage(MessageEvent event) {
        textField.setText(event.message);
    }
    
    • ThreadMode: MAIN_ORDERED

    订阅者(Subscriber) 在主线程中执行响应事件的方法 和 ThreadMode: MAIN 区别在于,不管 发布者(Publisher) post 事件是什么线程 ,MAIN_ORDERED会把事件加入到主线程的消息循环队列中执行,而不会直接调用处理消息的方法

    // Called in Android UI's main thread
    @Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
    public void onMessage(MessageEvent event) {
        textField.setText(event.message);
    }
    
    • ThreadMode: BACKGROUND

    订阅者(Subscriber) 在子线程中执行响应事件的方法.若 发布者(Publisher) post 事件为主线程,则在后台子线程中执行.所有的 ThreadMode: BACKGROUND 事件要转化在子线程处理的都共用一个相同的后台子线程 ,若 发布者(Publisher) post 事件的线程为子线程,则就直接在 post 事件的线程中处理.

    // Called in the background thread
    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onMessage(MessageEvent event){
        saveToDisk(event.message);
    }
    
    • ThreadMode: ASYNC

    订阅者(Subscriber) 在独立的子线程中执行响应事件的方法,既不是 发布者(Publisher) post 事件的线程,不是主线程,也不是 ThreadMode: BACKGROUND 的后台子线程 .发布者(Publisher) post 事件的线程不会等待订阅者(Subscriber) 处理事件的线程响应.适用于处理事件时间较长的情况

    // Called in a separate thread
    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void onMessage(MessageEvent event){
        backend.send(event.message);
    }
    
    3.2. EventBus 配置
    EventBus eventBus = EventBus.builder()
        .logSubscriberExceptions(false) // 默认为 ture  是否记录 调用订阅者响应事件的方法出现异常时的异常日志
        .logNoSubscriberMessages(false) // 默认为 ture  是否记录 发布者(Publisher) 发布事件时没有订阅者(Subscriber)  的日志 
        .sendNoSubscriberEvent(false) // 默认为 ture 当发布者(Publisher) 发布事件时没有订阅者(Subscriber) 是否将事件转化为 post 一个 NoSubscriberEvent事件
        .sendSubscriberExceptionEvent(false) // 默认为 ture 调用订阅者响应事件的方法出现异常时 是否 post 一个SubscriberExceptionEvent 事件
        .throwSubscriberException(BuildConfig.DEBUG) // 默认为 false 调用订阅者响应事件的方法出现异常时是否抛出 EventBusException
        .eventInheritance(false) // 默认为 ture 若 发布者(Publisher) 发布的事件是订阅者(Subscriber) 的订阅事件的子类,是否将事件传递给订阅者(Subscriber) 处理
        .ignoreGeneratedIndex(true) //默认为 false 是否忽略 Index 
        .strictMethodVerification(true) // 默认为 false ,是否严格认证 @Subscribe 注解标注的订阅者响应事件方法,如果 方法是0个或多于1个参数,或者是 非 public, 抽象的,静态的,会抛出 EventBusException
        .installDefaultEventBus();
    
    3.3. Sticky 事件

    Sticky 事件不同之处在于,当事件发布后,再有订阅者开始订阅该类型事件,依然能收到该类型事件最近一个 Sticky 事件。

    • 订阅Sticky事件
    // UI updates must run on MainThread
    @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
    public void onEvent(MessageEvent event) {   
        textField.setText(event.message);
    }
    
    • 发布Sticky事件
    EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!"));
    
    • 移除Sticky事件

    Sticky事件 在事件发布之后依然会接收的到,所以不会丢失,若不需要时必须手动移除

    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
    }
    

    移除 Sticky事件 还有一个重载的方法

    MessageEvent stickyEvent = EventBus.getDefault().removeStickyEvent(MessageEvent.class);
    // Better check that an event was actually posted before
    if(stickyEvent != null) {
        // Now do something with it
    }
    
    3.4. 优先级和取消事件传递
    • 优先级

    默认优先级是 0,高优先级的的订阅者先接收到事件.只有相同在ThreadMode 下才能比较优先级 不同的 ThreadMode下的订阅者的优先级别不起作用

    @Subscribe(priority = 1);
    public void onEvent(MessageEvent event) {
        ...
    }
    
    • 取消事件传递

    只有 和 发布者(Publisher) post 事件相同的线程的 订阅者(Subscriber) 才能取消事件传递,不然的话会报异常

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

    Index是 EventBus 3 上添加的新特性,默认是用使用反射,而 Index 是编译时 使用 annotationProcessor 生成辅助的 SubscriberInfoIndex 类 ,里面会记录订阅者信息,就不用反射扫描类中方法的,所以 Android上推荐使用 Index ,效率更高

    • 使用 annotationProcessor 生成 Index
    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'
    }
    
    • 使用 index

    配置好 annotationProcessor 后使用 index 和之前的唯一区别是 EventBus.getDefault()之前必须使用 addIndex 方法进行初始化

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

    AsyncExecutor是一个辅助类会创建一个线程池,在 RunnableEx 里面执行出现异常会被捕获不用自己处理,并被转化为一个 ThrowableFailureEvent事件并 post 出去

    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
    }
    

    相关文章

      网友评论

          本文标题:EventBus 3.X 的使用

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