1. 引入EventBus
implementation 'org.greenrobot:eventbus:3.1.1'
2. 注册和注销EventBus
//注册位置:onCreate 或者 onStart
EventBus.getDefault().register(object);
//不使用的时候记得unregister onDestroy 或者 onStop
EventBus.getDefault().unregister(object);
3. 订阅或者发布事件
//注册的object内部实现
//func 函数名称,用户自己定义
//T event ,T 表示某个类型事件,T可以是基本类型,也可以是class,不同的类表示不同的事件(注意继承关系)
//threadMode 不同,响应行为不一样,后面解释
@Subscribe(threadMode = ThreadMode.MAIN)
public void func(T event ){};
//发布事件,一般使用Post,稍后讲解postSticky
//调用post方法的时候,如果订阅者和post在同一线程则post将等所有消费者完成之后返回。
//如果不在同一线程则将事件投递到pendingqueue的队列
//(mainThreadPoster,backgroundPoster,asyncPoster)里面去之后再去触发事件。
EventBus.getDefault().post(T event);
//事件订阅者在事件发布之后注册的也能接收到该事件的特殊类型,订阅者必须指定sticky = true
//只保留最后一个sticky事件
//@Subscribe(sticky = true,threadMode = ThreadMode.MAIN_ORDERED)
//public void func(T event ){};
EventBus.getDefault().postSticky(T event);
4. ThreadMode 的五种模式
-
ThreadMode.MAIN
- 订阅者方法将在主线程(UI线程)中被调用
- 如果发布事件的线程是主线程,那么该模式的订阅者方法将被直接调用否则进入队列
- 使用该模式的订阅者方法必须快速返回,不应该做耗时的操作,以避免阻塞主线程(如果主线程是Poster)
-
ThreadMode.MAIN_ORDERED
- 订阅者方法将在主线程(UI线程)中被调用
- 事件将先进入队列然后才发送给订阅者,所以发布事件的调用将立即返回
- 使用该模式的订阅者方法必须快速返回,不应该做耗时的操作,以避免阻塞主线程(如果主线程是Poster)
- 不同的线程发送消息,先加入队列的会优先执行
-
ThreadMode.BACKGROUND
- 每一个订阅者方法将在后台同一个线程中被调用
- 如果发布事件的线程不是主线程,那么订阅者方法将直接在该线程中被调用
- 如果发布事件的线程是主线程,那么将使用一个单独的后台线程,该线程将按顺序发送所有的事件
-
ThreadMode.POSTING
- 默认的线程模式
- 订阅者将在发布者的线程中被调用(同步的,只有所有订阅者处理完成之后post才返回)
-
ThreadMode.ASYNC
- 保证每个订阅者方法将在一个独立的子线程中被调用
- 发布事件的调用将立即返回
- 避免触发大量的长时间运行的订阅者方法,以限制并发线程的数量
- EventBus使用了一个线程池来有效地重用已经完成调用订阅者方法的线程。
配合下面部分post调度源码将更加清楚(invokeSubscriber直接在当前线程调用)。
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
5. 多继承的子类订阅事件分析(以String为例)
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
....
}
EventBsu.java
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//获取Event的Class
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
//获取Event的所有父类
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
//投递所有父类Event
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
}
...
}
此时注意eventTypes 的size和值
所以如果我们订阅了以上五种class,那么 EventBus.getDefault().post(String);
将被以上订阅者接受。至于接受顺序和ThreadMode相关。eg:ThreadMode.MAIN_ORDERED,那么订阅者顺序则为String->Serializable->Comparable->CharSequence->Object
即:Sting的继承顺序。
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(String event) {
Log.i("", "Subscribe Recv String Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);
}
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(Serializable event) {
Log.i("", "Subscribe Recv Serializable Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);
}
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(Comparable event) {
Log.i("", "Subscribe Recv Comparable Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);
}
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(CharSequence event) {
Log.i("", "Subscribe Recv CharSequence Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);
}
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(Object event) {
Log.i("", "Subscribe Recv Object Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);
}
6. ASYNC 模式保证每个订阅者都是独立的线程和是否多继承没关系
6. BACKGROUND 每一个订阅者方法将在后台同一个线程中被调用
7. 订阅者不同类型情景
1.进入队列顺序:多继承:子类->父类继承顺序。eg:String->Serializable->Comparable->CharSequence->Object
2.进入队列情况,根据不同订阅类型来决定。
3.执行顺序根据线程的cpu调度决定。
eg:以在UI线程Post(String)
t为例,分析下列事件调用线程和执行顺序情况。
//进入UI线程队列
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(String event) {}
//不进入队列,直接执行,所以会优先于事件String 执行
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMainModeEvent(Serializable event) {}
//不进入队列,直接执行,由于Comparable 顺序在Serializable 后面,所以会优先
//事件String 执行d但是在事件Serializable 之后执行,该事件执行完成之后Post返回。
@Subscribe(threadMode = ThreadMode.POSTING)
public void onMainModeEvent(Comparable event) {}
//进入后台线程,执行顺序由cpu调度决定
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onMainModeEvent(CharSequence event) {}
//进入后台线程,执行顺序由cpu调度决定
@Subscribe(threadMode = ThreadMode.ASYNC)
public void onMainModeEvent(Object event) {}
上述事件将在三个线程中完成,分别是UI,thread1,thread2.每个线程中的执行内容和顺序如下:
UI
- Serializable 事件
- Comparable 事件
- String 事件
thread1
- CharSequence 事件
thread2
- Object 事件
7. postSticky
- postSticky
- 只保留最后一个投递的消息
- 凡是在该事件投递之后注册的Object依然可以接受到Event,不论该Event是否被其他订阅过
SecoundActivity.java
public void onClick(View v) {
Intent intent = new Intent(SecoundActivity.this,ThirdActivity.class);
startActivity(intent);
EventBus.getDefault().postSticky("sticky0");
}
@Subscribe(sticky = true,threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(String event) {
Log.i("SecoundActivity", "MAIN_ORDERED : Subscribe Recv String Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);
}
ThirdActivity.java
@Subscribe(sticky = true,threadMode = ThreadMode.MAIN_ORDERED)
public void onMainModeEvent(String event) {
Log.i("ThirdActivity", "MAIN_ORDERED : Subscribe Recv String Event ,thread id: " + Thread.currentThread().getId() + ",event message:" + event);
}