EventBus3 学习笔记

脑图

EventBus学习笔记

概述

EventBus 是一款针对Android优化的发布/订阅(publish/subscribe)事件总线。主要功能是替代Intent,Handler,Broadcast在Fragment,Activity,Service,线程之间传递消息。简化了应用程序内各组件,组件与后台线程间的通信。优点代码简洁,以及将发送者和订阅者解耦。

基本使用

使用步骤

  • 添加依赖
  • 定义事件
  • 注册/取消订阅
  • 发送事件

添加依赖

1
compile 'org.greenrobot:eventbus:3.0.0'

定义事件

这里的事件是一个任意的POJO 没有任何要求

1
2
3
4
5
6
7
8
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}

订阅

准备订阅者

使用注解 @Subscribe ,在3.0中对方法名称没有任何要求 当发送事件时EventBus会调用方法

1
2
3
4
5
6
7
8
9
10
11
// This method will be called when a MessageEvent is posted (in the UI thread for Toast)
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
// This method will be called when a SomeOtherEvent is posted
@Subscribe
public void handleSomethingElse(SomeOtherEvent event) {
doSomethingWith(event);
}

注册/取消订阅

1
2
3
4
5
6
7
8
9
10
11
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}

发送事件

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

官网指南 http://greenrobot.org/eventbus/documentation/how-to-get-started/

交付线程 Delivery Threads (ThreadMode)

EventBus 通过 threadMode 决定订阅事件 在哪个线程处理,threadMode的取值 有四个枚举类型

  • POSTING
  • MAIN
  • BACKGROUND
  • ASYNC

POSTING。 默认值,将会与发送线程一致,发送事件在哪个线程,订阅者就在哪个线程处理

1
2
3
4
5
6
7
// Called in the same thread (default)
// ThreadMode is optional here
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMessage(MessageEvent event) {
log(event.message);
}

MAIN 。 UI线程,订阅者将会在UI线程处理

1
2
3
4
5
6
// Called in Android UI's main thread
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessage(MessageEvent event) {
textField.setText(event.message);
}

BACKGROUND 。 后台线程处理,如果发送者在UI线程发出就会另开线程处理,否则就直接在同一线程处理,不会在UI线程处理就对了

1
2
3
4
5
6
// Called in the background thread
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMessage(MessageEvent event){
saveToDisk(event.message);
}

ASYNC 。异步,订阅者将会另开一个线程处理,无论发送者从哪个线程发出

1
2
3
4
5
6
// Called in a separate thread
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMessage(MessageEvent event){
backend.send(event.message);
}

官网指南 http://greenrobot.org/eventbus/documentation/delivery-threads-threadmode/

优先级及事件取消 Priorities and Event Cancellation

优先级

EventBus 通过 priority 属性决定优先级 ,默认0 值越高 优先级越高。

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

事件取消

EventBus 通过 cancelEventDelivery(Object event) 取消事件,这可是优先级高的特权了。

1
2
3
4
5
6
7
8
9
// Called in the same thread (default)
@Subscribe
public void onEvent(MessageEvent event){
// Process the event
...
// Prevent delivery to other subscribers
EventBus.getDefault().cancelEventDelivery(event) ;
}

官网指南 http://greenrobot.org/eventbus/documentation/priorities-and-event-cancellation/

配置 Configuration

一般我们使用 EventBus.getDefault() 得到EventBus实例,
如果有别的需求可以使用 EventBusBuilder 类构建EventBus,例如 关闭log

1
2
3
4
EventBus eventBus = EventBus.builder()
.logNoSubscriberMessages(false)
.sendNoSubscriberEvent(false)
.build();

或者说 当订阅者抛出异常时 发送 SubscriberExceptionEvent 事件

1
EventBus eventBus = EventBus.builder().throwSubscriberException(true).build();

默认情况下 订阅者抛出异常EventBus会捕获异常并发一个 SubscriberExceptionEvent 事件

我们可以通过 installDefaultEventBus()方法我们的配置放到默认实例上;但是要在使用 EventBus.getDefault()之前

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

官网指南 http://greenrobot.org/eventbus/documentation/configuration/

粘性事件 Sticky Events

对于一般的事件,我们首先要注册订阅者,然后发送事件,订阅者才能收到事件。如果先发送事件,再订阅此事件,将收不到事件,而粘性事件恰恰相反,粘性事件是可以先发送,然后再注册订阅者,后注册的订阅者依然可以接收到事件(ps:在发送前注册的也可以收到)

先发送粘性事件

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

再启动一个Activity 仍然可以接受到之前发送的事件

属性 sticky 的取值决定是否是粘性事件

ps:你不注册的话,啥事件也是收不到的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@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();
}

移除粘性事件

如果你不移除粘性事件,那么它将一直存在,直到你程序被杀死

1
2
3
4
5
6
7
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
}

官网传送门 http://greenrobot.org/eventbus/documentation/configuration/sticky-events/

订阅索引 Subscriber Index

订阅索引是3.0中的新特性,是可选项。

在3.0中由于使用了注解,比起使用反射来遍历方法的2.4版本逊色不少。但开启索引后性能远远超出旧版本。
看作者放出的图

EventBus性能对比

既然使用索引后那么叼,那就看看怎么使用索引

注意项

  • 只有@Subscribe 可以被索引,必须是 public修饰
  • 不能再内部类中

使用 apt插件的方式

  • 顶级 build.gradle 中加入
1
2
3
4
5
6
buildscript {
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
  • 再module的build.gradle 中使用 apt插件
1
2
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
  • module的build.gradle 添加依赖
1
2
3
4
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
apt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
  • module 的 build.gradle 配置参数 ,这里写自己的包名
1
2
3
4
5
apt {
arguments {
eventBusIndex "com.example.myapp.MyEventBusIndex"
}
}

使用索引

编译过后 会生成 MyEventBusIndex类,没有生成就多编译几遍

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

将索引配置到默认实例中

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

还可以添加多个不同的library中索引

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

官网指南 http://greenrobot.org/eventbus/documentation/subscriber-index/

混淆 ProGuard

1
2
3
4
5
6
7
8
9
10
-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);
}

官网指南 http://greenrobot.org/eventbus/documentation/proguard/

AsyncExecutor

懒得翻译了,直接看吧
http://greenrobot.org/eventbus/documentation/asyncexecutor/

参考

感谢各位大神的分享

Demo地址: https://github.com/sky-mxc/AndroidDemo/tree/master/event