EventBus初体验

2020-03-19 16:51:27 浏览数 (1)

前言

本文主要给大家讲述下本人使用EventBus的经验和体会。EventBus是一款针对Android的发布/订阅事件总线的开源框架。它可以让我们很轻松地在Android各个组件之间传递消息,并且代码的可读性更好,耦合度更低。

提示:文中链接需要点击文章末尾处阅读原文才能点击。

1

Android开发中遇到的问题

  1. 在一个Activity中,多个Fragment嵌套, 需要监听嵌套的Fragment中的内容变化, 如下图

FragmentA需要监听NestFragment中view的变化。这种嵌套太深的情况下会使逻辑处理变得很复杂。那么我们该如何传递事件?

  1. 数据预加载的问题。首页有大量数据需要请求网络, 而欢迎界面有1s停顿, 需要把首页的网络请求放到欢迎界面发送, 但要首页能接收到欢迎界面请求数据后的回调。这种情况该怎么处理?
  2. app架构上, 数据层和和视图层该如何解耦?

2 什么是EventBus

本文的EventBus,是指greenrobot的 EventBus, 主要根据EventBus3.0 讲解; EventBus事件总线是指用于简化Android程序内各个组件和线程之间的事件传递的一种机制。

订阅发布模式指的是将事件的接收者和发布者解耦,一旦Publisher发出消息,Subscriber自己按需改变。我个人喜欢把它拿来和BroadCast比较; 整个流程示意图如下:

Publisher: 事件发送者,事件产生的地方。 Subscriber: 事件接收者, 接收处理事件的地方。每个Publisher发送事件, 都通过EventBus把事件分发到各个Subscriber, 同时Pulisher和Subscriber之间保持透明。 整个流程跟广播类似, Publisher发送事件,就类似我们发送一个广播, 在接收广播的地方进行注册, 我们就可以接收广播发出来的事件, 然后就可以处理。Subscriber就类似广播处理器。

3 使用场景

  1. 复杂逻辑下的对象传递;
  2. 函数的调用者与被调用者需要低耦合,或者框架设计之初,无法预料到的调用。

eg. 上面的使用场景,以前在我们代码中时常出现的场景就是:监听器的传递,回调函数和各种Listener。

4

怎么使用

1

在gradle中添加依赖

代码语言:javascript复制
dependencies {
 compile 'org.greenrobot:eventbus:3.0.0'
 }

2

注册和取消注册

在要接收消息的类中调用register和unregister方法, 这两个方法成对使用。这种使用方法和广播相类似, 一般在Activity的 onCreate 和 onDestory 方法中进行;

代码语言:javascript复制
  EventBus.getDefault().register( this );
 EventBus.getDefault().unregister( this );

3

声明处理消息的函数

在接收消息的函数上,加上 '@Subscribe' 注解,代表在哪个线程进行处理,此注解还可以带上额外的参数。EventBus是按函数参数的类型确认消息的接收者的, 此函数只能有且仅有一个参数;

  • threadMode 用于指定此函数运行的线程, 是一个Enum, 有4个常量。包含MAIN、BACKGROUND 、ASYNC和 POSTING, 默认为POSTING。
  • ThreadMode.MAIN 在主线程中运行。
  • ThreadMode.POSTING 跟消息发送者在同一线程运行。
  • ThreadMode.BACKGROUND 后台线程, 如果发送消息的线程就是后台线程,就直接执行; 如果不是, 则会把消息放在队列中,依次执行。
  • ThreadMode.ASYNC 后台线程, 消息会在单独的线程中执行,用了线程池,多个消息会同时执行。
  • priority 优先级, 值越小优先级越低,当有多个方法处理同一个消息时,处理的顺序,默认为0。
  • sticky 是否接收黏性消息, 和黏性广播相同, 默认为false。
代码语言:javascript复制
@Subscribe(threadMode = ThreadMode.MAIN, priority = 1, sticky = false)
 public void onEvent( TestEvent  testEvent ){    
    Log.e( "zy", ">>>> receiverEvent");
 }

4

发送消息

所谓的消息发送消息就是把一个java对象传递给处理消息的函数。 EventBus消息和EventBus的对象实例有关, 用一个EventBus对象发送的消息,必须是用同一个EventBus对象注册的才能收到消息;

代码语言:javascript复制
  // 发送黏性消息
 EventBus.getDefault().postSticky( new TestEvent() );
 // 发送普通的消息
 EventBus.getDefault().post( new TestEvent() );

代码中可以看到,发送的消息有两种。sticky黏性消息:当消息发送出去之后,如果没有消息接收者处理这个消息,此消息会暂时存储在EventBus实例中, 当后面注册消息接受者时,如果是相应的处理者, 将会把消息给处理者去处理;我个人喜欢用这个来做数据的预加载;

5

提升性能

注解处理能加快编译速度。由于Android机器本身性能有限,一般不建议使用运行时注解,虽然EventBus的注解声明为Runtime, 但它同时支持编译时注解和运行时注解, 当没配置编译时注解处理器时, 会自动通过反射查找运行时的注解。

5.1 添加注解处理器依赖:

代码语言:javascript复制
buildscript {
...
dependencies {
   classpath 'com.android.tools.build:gradle:2.1.0'
   // 在最外层添加gradle的插件依赖
   classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
   }
   ...
}
// 项目中 增加注解处理器插件
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 {
   // 注解处理器 最终生成的java文件位置
   eventBusIndex "com.zy.test.MyEventBusIndex"
   }
}

5.2 初始化EventBus时, 使用注解处理器生成的类文件:

代码语言:javascript复制
mEventBus = EventBus.builder().addIndex( new MyEventBusIndex() ).build();

EventBus的消息和EventBus实例有关系, 自己配置的EventBus实例,一般需要用单例保存, 确保发送和接收消息的地方,使用的是同一个实例。

5

关于其他的一些细节

  • 消息处理者的继承 EventBus的消息处理者,是可以继承的。父类中的消息处理器, 在子类中仍可使用; 这是一个比较好的功能。比如一个通用的消息接收处理器,我们在BaseActivity中声明一次, 子类都可以使用了; 在构建Eventbus实例时, 调用 'EventBus.builder().eventInheritance( false )' ; 官方的说法是关闭后可以提高20%的性能。
  • 黏性消息 这是一个非常实用的功能, 我一般用来做预加载数据; 每种消息类型,最多存储一个黏性消息, 和黏性广播类似; 虽然消息处理者声明为'sticky = true', 但是依然可以接收普通消息。
  • 进程间的通讯 Eventbus的发送消息和消息处理是和Eventbus实例有关的, 是无法跨进程传递消息的; 如果涉及到进程间通讯, 还是要使用Android系统的接口。

6 对比

  • Broaddcast 优点: 可以指定运行线程, 消息处理可继承, 代码简单, 消息处理可继承, 低延迟, 对消息数据无要求(不需要实现Parcelable或者Serializable接口); 缺点: 无法跨进程。
  • LocalBroadcastManager 这个除了广播的低延迟外, Boardcast的缺点都有, 并且它还不能跨进程, 没有黏性广播。
  • RxBus RxBus并不是指某个框架, 泛指用Rxjava实现的,类似EventBus的功能; 一般使用PublishSubject 构建Rx对象, 使用ofType按区分事件类型。相比起来, Eventbus上手简单, 可继承, 有黏性事件; 而Rx可以有统一的异常处理, 可以对消息数据进行变换处理。但由于RxJava本身的学习难度高,不易上手。

小贴士

本文版权归Open软件开发小组所有,如需转载请联系主编申请授权。

0 人点赞