EventBus是一个通过发布、订阅事件实现组件间消息传递的工具。
它存在的目的,就是为了优化组件之间传递消息的过程。传统组件之间传递消息的方法有使用广播,回调等,而这些方法使用都比较复杂。
工作原理:
依赖:
dependencies {
compile 'org.greenrobot:eventbus:3.0.0'
}
注:EventBus是事件-订阅模型,实际上事件就是消息,订阅就是接收,本文不会很严格区分,方便理解为主!
1. 从简单的入手:充当Handler
既然能发送消息,那么自然在同一个组件下也能进行消息的发送和接收,也就是Handler的职责。
先定义一个事件的对象:
public class MessageEvent {
private String message; public MessageEvent(String message) {
this.message = message;
} public String getMessage() {
return message;
} @Override
public String toString() {
return message;
}
}
这个事件对象只需要是Object的子类,没其他要求,消息的内容可以随意定,这里用一个String表示事件的消息,toString直接输出事件的内容。
在需要接收消息的组件中,进行EventBus的绑定,这里由Activity充当订阅者(Subscriber),也就是消息接收者。
public class MainActivity extends AppCompatActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} @Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this); // 将当前Activity绑定为订阅者
} @Override
protected void onStop() {
EventBus.getDefault().unregister(this); // 解绑
super.onStop();
} // 声明一个订阅方法,用于接收事件
@Subscribe
public void onEvent(MessageEvent messageEvent) {
Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]");
} }
通过EventBus.getDefault方法获取到一个EventBus的一个单例,也就是每次调用这个方法得到的都是同一个EventBus对象。而不同的EventBus对象消息不会互通。
接着需要在Activity的onStart方法中进行对EventBus对象的绑定,在onStop方法中进行解绑。同时,需要定义用于接收事件的方法,并加上@Subscribe注解表明该方法用于接收订阅事件。
接着,我们需要发送事件:
EventBus.getDefault().post(new MessageEvent("I m Fndroid"));
这里获取的默认的EventBus对象,通过post方法进行事件的发送,log如下:
2. 组件间通讯:代替广播、回调等
EventBus的存在,并不是为了替代Handler,而是用来进行组件间的通讯。有了上面的知识,接下来就不难了。
我们都知道,只要是同一个EventBus对象绑定的组件(Subscriber),消息是互通的,也就是我们可以在Service中向Activity发送事件进行通讯。(其他组件类似)
定义一个IntentService,并且发送一个事件,而Activity,和上面一样。
public class MyIntentService extends IntentService { public MyIntentService() {
super("MyIntentService");
} @Override
protected void onHandleIntent(Intent intent) {
EventBus.getDefault().post(new MessageEvent("From service"));
} }
在Activity中开启服务:
startService(new Intent(this, MyIntentService.class));
Log:
组件间的通讯变得如此简单了。
3. 进阶:持久事件、线程模式、优先级
① 持久事件(StickyEvent):对于调用post方法发送的普通消息,会在第一次被接收到的时候被消费掉,也就是我们在@Subscribe方法下处理完了,这个消息就消失了。而EventBus则提供了另一种类型的消息——StickyEvent,这个消息,会被保存在RAM中,直到下一个StickyEvent被发送才会被替换。每个EventBus对象都能通过geStickyEvent方法获取最近发出的持久事件。
我们对Activity稍作修改,在订阅方法中,把当前的持久消息打印出来:
// 声明一个订阅方法,用于接收事件
@Subscribe
public void onEvent(MessageEvent messageEvent) {
Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]");
Log.d(TAG, "onEvent: Sticky Event = [" + EventBus.getDefault().getStickyEvent(MessageEvent.class) + "]");
}
接着对Service也进行修改,令其发送一个StickyEvent:
@Override
protected void onHandleIntent(Intent intent) {
EventBus.getDefault().post(new MessageEvent("From service"));
EventBus.getDefault().postSticky(new MessageEvent("From service2"));
EventBus.getDefault().post(new MessageEvent("From service3"));
}
这里看到,在第二次发送的时候,调用了postSticky方法发送事件,这就表明了该事件是一个持久事件,除非有新的同类型(不同类型的事件可以共存)持久事件被发送,否则会一直被保存在内存中,我们任何时候都能获取得到。
Log:
可以看到,在第三次接收到消息的时候,将StickyEvent打印出来,依旧是"From service2"。
同样的,如果我们想要移除此持久事件,可以调用EventBus的removeStickyEvent方法来实现,如果要移除所有类型的持久事件,可以调用removeAllStickyEvent方法。
② 线程模式
EventBus允许我们对订阅者进行线程设置,默认情况下,订阅是和事件发送处于同一线程的,我们不妨把订阅的线程id打印出来看一看。
修改Activity中的@Subscribe方法:
@Subscribe
public void onEvent(MessageEvent messageEvent) {
Log.d(TAG, "onEvent: Thread id = [" + Thread.currentThread().getId() + "]");
Log.d(TAG, "onEvent() called with: messageEvent = [" + messageEvent + "]");
}
修改Service,让其发送一次普通事件,并且输出当前线程id:
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: Thread id = [" + Thread.currentThread().getId() + "]");
EventBus.getDefault().post(new MessageEvent("From service"));
}
打印Log:
对于订阅者,有以下四种线程模式:
- POSTING:默认模式,订阅和事件发送在同一线程下进行
- MAIN:订阅在主线程下进行,可以直接修改UI
- BACKGROUND:如果事件发送在主线程,则订阅在子线程下进行,如果事件发送在子线程,则订阅也在该子线程中进行
- ASYNC:如果事件发送在主线程,则订阅在子线程下进行,如果事件发送在子线程,则订阅会在其他子线程中进行
设置订阅者线程很简单,只需要在注解中赋值即可,如:
@Subscribe(threadMode = ThreadMode.MAIN)
③ 优先级
每个组件中可以有多个订阅方法,而我们可以对它们设置不同的优先级,设置的方法也很简单:
@Subscribe(priority = 88)
默认的优先级为0,更高优先级的订阅方法会更先收到事件,而每个订阅方法都可以对事件进行终止,可以通过以下方法停止事件传递:
EventBus.getDefault().cancelEventDelivery(messageEvent);
④ 自定义EventBus对象
通过getDefault方法获取的是一个EventBus默认的单例,而我们可以通过EventBus.Builder来构造一个自定义的EventBus对象。
明白了用法以后,我们分析源码也会更加简单。