EventBus基本使用与进阶配置

   日期:2020-08-25     浏览:90    评论:0    
核心提示:介绍EventBus是适用于Android和Java的发布/订阅事件总线。可简化活动,片段,线程,服务等之间的通信。代码更少,质量更高。基本使用项目配置EventBus依赖 implementation org.greenrobot:eventbus:3.2.0定义事件 public class MessageEvent { }注册/解除订阅者和定义接受事件的方法,在Android中应该根据组件生命周期进行注册/解注册@Override public void on

介绍

EventBus是适用于Android和Java的发布/订阅事件总线。可简化活动,片段,线程,服务等之间的通信。代码更少,质量更高。

基本使用

  • 项目配置EventBus依赖
 implementation 'org.greenrobot:eventbus:3.2.0'
  • 定义事件
 public class MessageEvent { }
  • 注册/解除订阅者和定义接受事件的方法,在Android中应该根据组件生命周期进行注册/解注册
@Override
  public void onStart() {
    super.onStart();
    // 注册订阅者
    EventBus.getDefault().register(this);
  }
  
  @Override
  public void onStop() {
    super.onStop();
    // 解除订阅者
    EventBus.getDefault().unregister(this);
  }
  
  // 定义接受事件的方法(可以指定线程模式、事件优先级、是否是粘性事件)
  @Subscribe(threadMode = ThreadMode.MAIN)  
  public void onMessageEvent(MessageEvent event){};
  
  • 发布事件
EventBus.getDefault().post(new MessageEvent());
  • 配置混淆(如果项目开启了混淆,则需要添加EventBus的混淆规则)
  -keepattributes *Annotation*
  -keepclassmembers class * {
      @org.greenrobot.eventbus.Subscribe <methods>;
  }
  -keep enum org.greenrobot.eventbus.ThreadMode { *; }
   
  # And if you use AsyncExecutor:
  -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
      <init>(java.lang.Throwable);
  }

自定义配置

使用 EventBusBuilder 类来配置 EventBus 的方方面面。进入 EventBus 类中,可以看到 EventBusBuilder 会给 EventBus 赋值几个默认为 true 的属性配置值。

  boolean logSubscriberExceptions = true;// 打印订阅异常日志
  boolean logNoSubscriberMessages = true;// 打印没有订阅者的消息
  boolean sendSubscriberExceptionEvent = true;// 订阅方法异常时发送SubscriberExceptionEvent事件
  boolean sendNoSubscriberEvent = true;// 发送的消息没有订阅者时发送 NoSubscriberEvent 事件
  boolean eventInheritance = true;// 事件允许继承,设置true意思是去查找该事件父类的订阅者,执行调用
  boolean throwSubscriberException;// 回调订阅方法失败时,是否抛出异常
  boolean ignoreGeneratedIndex;//是否强制使用发射查找订阅方法,忽略注解处理器生成的订阅信息Index

全局 app 中我们一般是使用 EventBus.getDefault() 这样的单例,那么如何将我们想要更改后的配置应用于单例中,从而仍然使用 EventBus.getDefault()这样的简便写法?

EventBus.builder()
				.logSubscriberExceptions(false)
                .logNoSubscriberMessages(false)
                .sendSubscriberExceptionEvent(false)
                .sendNoSubscriberEvent(false)
                .throwSubscriberException(false)
                .installDefaultEventBus();

线程模式

  • ThreadMode.POSTING

订阅者的事件处理程序方法将在发布事件的同一线程中被调用。这是默认值。事件传递是同步完成的,发布完成后将调用所有订阅者。此ThreadMode意味着开销最少,因为它避免了线程的完全切换。因此,这是已知的简单任务的推荐模式,该任务在很短的时间内即可完成,而无需主线程。使用此模式的事件处理程序应快速返回,以避免阻塞可能是主线程的发布线程。

  • ThreadMode.MAIN

    订阅者的事件处理程序方法将在Android的主线程(有时称为UI线程)中调用。如果发布线程是主线程,则将直接调用事件处理程序方法(与ThreadMode.POSTING所述的同步)。使用此模式的事件处理程序必须快速返回以避免阻塞主线程。例:

@Subscribe(threadMode = ThreadMode.MAIN)
  public void onMessage(MessageEvent event) {
      textField.setText(event.message);
  }
  • ThreadMode.MAIN_ORDERED

    订阅者的事件处理程序方法将在Android的主线程中调用。该事件始终排入队列,以便以后交付给订户,因此投递呼叫将立即返回。这使事件处理具有更严格和更一致的顺序(因此名称为MAIN_ORDERED)。例如,如果您在具有MAIN线程模式的事件处理程序中发布另一个事件,则第二个事件处理程序将在第一个事件处理程序之前完成(因为它被同步调用–将它与方法调用进行比较)。使用MAIN_ORDERED,第一个事件处理程序将完成,然后第二个事件处理程序将在稍后的时间点调用(一旦主线程具有容量)。使用此模式的事件处理程序必须快速返回以避免阻塞主线程。例:

@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
  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);
  }

事件优先级/取消事件的分发

  • 事件的优先级

    @Subscribe中定义事件的优先级,看看@Subscribe中定义的属性

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD})
    public @interface Subscribe {
    
        ThreadMode threadMode() default ThreadMode.POSTING;//线程模式
      
        boolean sticky() default false;//是否是粘性事件,默认false
    
        int priority() default 0;// 事件优先级,默认0
    }
    

    默认的优先级为 0,对于同一个事件,优先级高的订阅者将比优先级低的先接收到事件。值得注意的是,条件是在同一个线程中(threadMode 一致),在不同的 threadMode 值的订阅者之间的接受顺序并不会有影响。

  • 取消事件的分发
    EventBus 中提供 cancelEventDelivery(Object event) 来取消事件的进一步分发,则接下来的订阅者将不会收到事件。一般的情景都是用于发送事件,然后在优先级高的订阅者中处理完自己逻辑,之后不然让事件继续分发给其他的订阅者,则取消事件。需要注意的是取消操作,被限制在只能使用 threadMode 为 ThreadMode.POSTING 中。

  • 粘性事件(StickyEvent)
    一般的事件发布之后,当前所有已注册该事件类型的订阅者都将收到该事件。这个很容易理解,EventBus 遍历那些已经注册过的订阅者,然后调用订阅者的接受事件的方法。而sticky 事件在发布之后,仍然允许后来注册的订阅者响应函数去响应对应类型的 sticky 事件,sticky 事件在事件发布后,如果后来的订阅者再去订阅该类型事件,仍然可以收到该类型最近的一个 sticky 类型,因为它已经被预先存储在内存之中了。

    • 发送粘性事件
      • postSticky(Object event)
    • 获取粘性事件
      • getStickyEvent(Class eventType)
    • 移除粘性事件
      • removeStickyEvent(Class eventType)
      • removeStickyEvent(Object event)
      • removeAllStickyEvents()

使用优化

  • 订阅者索引
    Subscriber Index 是EventBus3的新特性,是用于加速初始化订阅者注册的一个优化。使用订阅者索引避免了运行时使用反射进行订阅方法的昂贵查找。相反,EventBus注释处理器会在构建时进行查找。Subscriber Index 在编译期间通过 EventBus annotation processor(注解处理器) 被创建起来的。这个特性并不是必须使用的,但是是被推荐的,因为通过这个可以更快速度获得订阅者,从而去触发响应事件。

  • 使用条件
    只有被 @Subscribe 注解的方法,且订阅者类和事件类都必须为 public 才可以被建立索引。同时,由于 java 注解技术限制,@Subscribe 在匿名内部类中是不会被识别的。当 EventBus 不能使用索引时,它将自动回退到在运行时进行反射查找订阅方法,因此 EventBus 仍然能够工作,只是稍微慢一点而已的。推荐去使用 Subscriber Index 在编译期间建立了订阅者索引,所以更快获得订阅者,以调用它的响应函数。而如果不设置 Subscriber Index 其实也能使 EventBus 工作的很好,虽然获得订阅者时通过反射是慢了一点点而已,但仍然会帮助将订阅者缓存起来。

  • 生成索引

  // app build.gradle文件夹下配置
    
    // Java:using annotationProcessor
    android {
        defaultConfig {
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [ eventBusIndex : 'com.example.myapp.MyEventBusIndex' ]
                }
            }
        }
    }
     
    dependencies {
        def eventbus_version = '3.2.0'
        implementation "org.greenrobot:eventbus:$eventbus_version"
        annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbus_version"
    }
    
    =========================================================================
      
    // Kotlin: using kapt
    apply plugin: 'kotlin-kapt' // ensure kapt plugin is applied
     
    dependencies {
        def eventbus_version = '3.2.0'
        implementation "org.greenrobot:eventbus:$eventbus_version"
        kapt "org.greenrobot:eventbus-annotation-processor:$eventbus_version"
    }
     
    kapt {
        arguments {
            arg('eventBusIndex', 'com.example.myapp.MyEventBusIndex')
        }
    }
  • 使用索引
	// 至少build一次项目,为了让注解处理程序生成Index类文件
    
    // 第一种方式注入Index,然后直接构建出EventBus实例,这个全局使用即可。
    EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();
    
    // 第二种方式注入Index,之后还是通过EventBus.getDefault()获取,且只需要调用一次。
    EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
    EventBus eventBus = EventBus.getDefault();
    
    // 如果依赖库中需要支持订阅者,同样的配置原理生成Index,然后将其添加到EventBus中
    EventBus eventBus = EventBus.builder()
      	.addIndex(new MyEventBusAppIndex())
        .addIndex(new MyEventBusLibIndex()).build();
        
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服