EventBus是一款针对Android优化的发布-订阅事件总线。它简化了应用程序内各组件间、组件与后台线程间的通信。其优点是开销小,代码更优雅,以及将发送者和接收者解耦。</span></span>当一个Android应用功能越来越多的时候,保证应用的各个部分之间高效的通信将变得越来越困难。所以为了解决这个问题,EventBus应运而生!</p>
1.1 EventBus概述
在讲到 EventBus 的基本用法之前,我们需要了解 EventBus 的三要素以及它的 4 种ThreadMode。
EventBus的三要素如下。
• Event:事件。可以是任意类型的对象。
• Subscriber:事件订阅者。在 EventBus 3.0 之前消息处理的方法只能限定于 onEvent、onEventMainThread、onEventBackgroundThread和onEventAsync,它们分别代表4种线程模型。而在EventBus 3.0之后,事件处理的方法可以随便取名,但是需要添加一个注解@Subscribe,并且要指定线程模型(默认为POSTING)。
• Publisher:事件发布者。可以在任意线程任意位置发送事件,直接调用 EventBus 的post(Object)方法。可以自己实例化EventBus对象,但一般使用EventBus.getDefault()就可以。根据post函数参数的类型,会自动调用订阅相应类型事件的函数。
EventBus的4种ThreadMode(线程模型)如下。
• POSTING(默认):如果使用事件处理函数指定了线程模型为POSTING,那么该事件是在哪个线程发布出来的,事件处理函数就会在哪个线程中运行,也就是说发布事件和接收事件在同一个线程中。在线程模型为POSTING的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
• MAIN:事件的处理会在UI线程中执行。事件处理的时间不能太长,长了会导致ANR。
• BACKGROUND:如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行;如果事件本来就是在子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
• ASYNC:无论事件在哪个线程中发布,该事件处理函数都会在新建的子线程中执行;同样,此事件处理函数中禁止进行UI更新操作。
1.2 EventBus基本用法
EventBus基本使用分为以下5个步骤。
(1)自定义一个事件类
-
public
class
MessageEvent {
-
......
-
}
(2)在需要订阅事件的地方注册事件
EventBus.getDefault().register(this);
(3)发送事件
EventBus.getDefault().post(messageEvent);
(4)处理事件
-
@Subscribe(threadMode =
ThreadMode.
MAIN)
-
public
void
XXX(
MessageEvent messageEvent){
-
...
-
}
前面说过,在EventBus3.0以后消息处理的方法可以随便取名,但是需要加一个注解@Subscribe,并且要指定线程模型(默认为POSTING)。
(5)取消事件订阅
EventBus.getDefault().unregister(this);
1.3 EventBus实战
前面讲到了EventBus的基本用法,但是这过于简单,这里举一个例子来应用EventBus。
(1)添加依赖
implementation'org.greenrobot:eventbus:3.0.0'
(2)添加混淆规则
在模块的 proguard-rules.pro 混淆规则文件中添加如下规则:
-
-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);
-
}
(3)定义消息事件类
-
public
class
MessageEvent {
-
public
String message;
-
-
public
String
getMessage(
) {
-
return message;
-
}
-
-
public
void
setMessage(
String message) {
-
this.
message = message;
-
}
-
}
(4)注册和取消订阅事件
在MainActivity中注册和取消订阅事件,在 MainActivity 中定义了两个 Button:一个用来注册事件,另一个用来跳转到SecondActivity。代码如下:
-
public
class
MainActivity
extends
AppCompatActivity
implements
View.
OnClickListener {
-
private
TextView tv_message;
-
private
Button btn_enter_second_activity, btn_register_event;
-
-
@Override
-
protected
void
onCreate(
Bundle savedInstanceState) {
-
super.
onCreate(savedInstanceState);
-
setContentView(R.
layout.
activity_main);
-
tv_message =
findViewById(R.
id.
tv_message);
-
btn_enter_second_activity =
findViewById(R.
id.
btn_enter_second_activity);
-
btn_register_event =
findViewById(R.
id.
btn_register_event);
-
-
btn_enter_second_activity.
setOnClickListener(
this);
-
btn_register_event.
setOnClickListener(
this);
-
}
-
-
@Override
-
public
void
onClick(
View v) {
-
int id = v.
getId();
-
if (id == R.
id.
btn_enter_second_activity) {
-
// 跳转到SecondActivity
-
Intent intent =
new
Intent(
this,
SecondActivity.
class);
-
startActivity(intent);
-
}
else
if (id == R.
id.
btn_register_event) {
-
// 注册事件
-
EventBus.
getDefault().
register(
this);
-
}
-
}
-
-
-
@Override
-
protected
void
onDestroy(
) {
-
super.
onDestroy();
-
// 取消注册事件
-
EventBus.
getDefault().
unregister(
this);
-
}
-
-
-
}
(5)事件订阅者处理事件
在MainActivity中自定义方法来处理事件,在这里ThreadMode设置为MAIN,事件的处理会在UI线程中执行,用TextView来展示收到的事件消息。
-
@Subscribe(threadMode = ThreadMode.MAIN)
-
public void onEvent(MessageEvent event) {
-
if (
event !=
null &&
event.getMessage() !=
null) {
-
tv_message.setText(
event.getMessage());
-
}
-
}
(6)事件发布者发布事件
创建了SecondActivity来发布消息,在SecondActivity中,我们定义“发送事件 按钮来发送事件并将SecondActivity finish掉。代码如下所示:
-
public
class SecondActivity extends AppCompatActivity {
-
private
Button btn_send_event;
-
-
@Override
-
protected void onCreate(
Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(
R.layout.activity_second);
-
btn_send_event = findViewById(
R.id.btn_send_event);
-
btn_send_event.setOnClickListener(
new
View.
OnClickListener() {
-
@Override
-
public void onClick(
View v) {
-
MessageEvent event =
new
MessageEvent();
-
event.setMessage(
"欢迎学习EventBus");
-
EventBus.getDefault().post(event);
-
finish();
-
}
-
});
-
}
-
}
好了,运行程序,如图1-3-1所示。接下来我们点击MainActivity 中的“注册事件 按钮来注册事件,然后点击“跳转到SecondActivity按钮,这时跳转到SecondActivity,如图1-3-2所示。接下来点击“发送事件 按钮,这个时候 SecondActivity 被 finish 掉,因此界面展示的是MainActivity,如图1-3-3所示。可以看到MainActivity的TextView显示“欢迎学习EventBus",MainActivity成功地收到了SecondActivity发送的事件。
1.4 EventBus的黏性事件
-
@Subscribe(threadMode = ThreadMode.MAIN,sticky =
true)
-
public void onStickyEvent(MessageEvent event) {
-
if (
event !=
null &&
event.getMessage() !=
null) {
-
tv_message.setText(
event.getMessage());
-
}
-
}
-
btn_send_event.setOnClickListener(
new View.OnClickListener() {
-
@Override
-
public void onClick(View v) {
-
MessageEvent
event =
new MessageEvent();
-
event.setMessage(
"EventBus黏性事件");
-
EventBus.getDefault().postSticky(
event);
-
finish();
-
}
-
});
二 源码解析EventBus
2.1 EventBus构造方法
-
/** Convenience singleton for apps using a process-wide EventBus instance. */
-
public static EventBus getDefault() {
-
if (defaultInstance ==
null) {
-
synchronized (EventBus.
class) {
-
if (defaultInstance ==
null) {
-
defaultInstance =
new EventBus();
-
}
-
}
-
}
-
return defaultInstance;
-
}
-
/**
-
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
-
* central bus, consider {@link #getDefault()}.
-
*/
-
public EventBus() {
-
this(DEFAULT_BUILDER);
-
}
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
this调用了EventBus的另一个构造方法,如下所示:
-
EventBus(
EventBusBuilder builder) {
-
// 以事件类型作为Key,Subscription的List集合作为Value的Map集合
-
subscriptionsByEventType =
new
HashMap<>();
-
// 订阅者作为Key,订阅事件的List集合作为Value的Map集合
-
typesBySubscriber =
new
HashMap<>();
-
// 黏性事件的Map集合
-
stickyEvents =
new
ConcurrentHashMap<>();
-
// Handler对象,用于线程间切换
-
mainThreadPoster =
new
HandlerPoster(
this,
Looper.getMainLooper(),
10);
-
// Runnable对象
-
backgroundPoster =
new
BackgroundPoster(
this);
-
// Runnable对象
-
asyncPoster =
new
AsyncPoster(
this);
-
indexCount = builder.subscriberInfoIndexes !=
null ? builder.subscriberInfoIndexes.size() :
0;
-
subscriberMethodFinder =
new
SubscriberMethodFinder(builder.subscriberInfoIndexes,
-
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
-
logSubscriberExceptions = builder.logSubscriberExceptions;
-
logNoSubscriberMessages = builder.logNoSubscriberMessages;
-
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
-
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
-
throwSubscriberException = builder.throwSubscriberException;
-
eventInheritance = builder.eventInheritance;
-
executorService = builder.executorService;
-
}
2.2 订阅者注册
-
/**
-
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
-
* are no longer interested in receiving events.
-
* <p/>
-
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
-
* The {@link Subscribe} annotation also allows configuration like {@link
-
* ThreadMode} and priority.
-
*/
-
public
void
register(
Object subscriber) {
-
Class<?> subscriberClass = subscriber.
getClass();
-
List<
SubscriberMethod> subscriberMethods = subscriberMethodFinder.
findSubscriberMethods(subscriberClass);
// 1
-
synchronized (
this) {
-
for (
SubscriberMethod subscriberMethod : subscriberMethods) {
-
subscribe(subscriber, subscriberMethod);
// 2
-
}
-
}
-
}
-
List<
SubscriberMethod>
findSubscriberMethods(
Class<?> subscriberClass) {
-
// 从缓存中获取SubscriberMethod集合
-
List<
SubscriberMethod> subscriberMethods =
METHOD_CACHE.
get(subscriberClass);
// 1
-
if (subscriberMethods !=
null) {
-
return subscriberMethods;
-
}
-
//ignoreGeneratedIndex是否忽略注解器生成的MyEventBusIndex,默认为false
-
if (ignoreGeneratedIndex) {
-
//通过反射获取subscriberMethods
-
subscriberMethods =
findUsingReflection(subscriberClass);
-
}
else {
-
//通过注解器生成的MyEventBusIndex信息获取subscriberMethods,
-
//如果没有配置MyEventBusIndex,依然通过通过反射获取subscriberMethods
-
subscriberMethods =
findUsingInfo(subscriberClass);
// 3
-
}
-
if (subscriberMethods.
isEmpty()) {
-
throw
new
EventBusException(
"Subscriber " + subscriberClass
-
+
" and its super classes have no public methods with the @Subscribe annotation");
-
}
else {
-
METHOD_CACHE.
put(subscriberClass, subscriberMethods);
// 2
-
return subscriberMethods;
-
}
-
}
-
private
List<SubscriberMethod> findUsingInfo(
Class<?> subscriberClass) {
-
//创建和初始化FindState对象
-
FindState findState = prepareFindState();
-
findState.initForSubscriber(subscriberClass);
-
while (findState.clazz !=
null) {
-
//获取订阅者信息,没有配置MyEventBusIndex返回null
-
findState.subscriberInfo = getSubscriberInfo(findState);
// 1
-
if (findState.subscriberInfo !=
null) {
-
SubscriberMethod[]
array = findState.subscriberInfo.getSubscriberMethods();
// 2
-
for (SubscriberMethod subscriberMethod :
array) {
-
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
-
findState.subscriberMethods.add(subscriberMethod);
-
}
-
}
-
}
else {
-
//通过反射来查找订阅方法
-
findUsingReflectionInSingleClass(findState);
// 3
-
}
-
//进入父类查找订阅方法
-
findState.moveToSuperclass();
-
}
-
//回收处理findState,并返回订阅方法的List集合
-
return getMethodsAndRelease(findState);
-
}
-
private
void
findUsingReflectionInSingleClass
(FindState findState) {
-
Method[] methods;
-
try {
-
// This is faster than getMethods, especially when subscribers are fat classes like Activities
-
methods = findState.clazz.getDeclaredMethods();
// 1
-
}
catch (Throwable th) {
-
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
-
methods = findState.clazz.getMethods();
-
findState.skipSuperClasses =
true;
-
}
-
for (Method method : methods) {
-
//对订阅方法的类型进行过滤
-
int
modifiers
= method.getModifiers();
-
if ((modifiers & Modifier.PUBLIC) !=
0 && (modifiers & MODIFIERS_IGNORE) ==
0) {
-
Class<?>[] parameterTypes = method.getParameterTypes();
-
//定于方法中只能有一个参数
-
if (parameterTypes.length ==
1) {
-
//查找包含Subscribe的注解
-
Subscribe
subscribeAnnotation
= method.getAnnotation(Subscribe.class);
-
if (subscribeAnnotation !=
null) {
-
//保存到findState对象当中
-
Class<?> eventType = parameterTypes[
0];
-
if (findState.checkAdd(method, eventType)) {
-
ThreadMode
threadMode
= subscribeAnnotation.threadMode();
-
findState.subscriberMethods.add(
new
SubscriberMethod(method, eventType, threadMode,
-
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
-
}
-
}
-
}
else
if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
-
String
methodName
= method.getDeclaringClass().getName() +
"." + method.getName();
-
throw
new
EventBusException(
"@Subscribe method " + methodName +
-
"must have exactly 1 parameter but has " + parameterTypes.length);
-
}
-
}
else
if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
-
String
methodName
= method.getDeclaringClass().getName() +
"." + method.getName();
-
throw
new
EventBusException(methodName +
-
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
-
}
-
}
-
}
-
// Must be called in synchronized block
-
private
void
subscribe(
Object subscriber, SubscriberMethod subscriberMethod) {
-
// 获取订阅方法中的订阅事件
-
Class<?> eventType = subscriberMethod.
eventType;
-
// 创建一个SubScription来保存订阅者和订阅方法
-
Subscription newSubscription =
new
Subscription(subscriber, subscriberMethod);
// 1
-
//获取当前订阅事件中Subscription的List集合
-
CopyOnWriteArrayList<
Subscription> subscriptions = subscriptionsByEventType.
get(eventType);
// 2
-
if (subscriptions ==
null) {
-
//该事件对应的Subscription的List集合不存在,则重新创建并保存在subscriptionsByEventType中
-
subscriptions =
new
CopyOnWriteArrayList<>();
-
subscriptionsByEventType.
put(eventType, subscriptions);
-
}
else {
-
// 判断订阅者是否已经被注册
-
if (subscriptions.
contains(newSubscription)) {
-
throw
new
EventBusException(
"Subscriber " + subscriber.
getClass() +
" already registered to event "
-
+ eventType);
-
}
-
}
-
-
//将newSubscription按照订阅方法的优先级插入到subscriptions中
-
int size = subscriptions.
size();
-
for (int i =
0; i <= size; i++) {
-
if (i == size || subscriberMethod.
priority > subscriptions.
get(i).
subscriberMethod.
priority) {
-
subscriptions.
add(i, newSubscription);
// 3
-
break;
-
}
-
}
-
-
//通过订阅者获取该订阅者所订阅事件的集合
-
List<
Class<?>> subscribedEvents = typesBySubscriber.
get(subscriber);
// 4
-
if (subscribedEvents ==
null) {
-
subscribedEvents =
new
ArrayList<>();
-
typesBySubscriber.
put(subscriber, subscribedEvents);
-
}
-
//将当前的订阅事件添加到subscribedEvents中
-
subscribedEvents.
add(eventType);
-
-
// 黏性事件的处理
-
if (subscriberMethod.
sticky) {
-
if (eventInheritance) {
-
// Existing sticky events of all subclasses of eventType have to be considered.
-
// Note: Iterating over all events may be inefficient with lots of sticky events,
-
// thus data structure should be changed to allow a more efficient lookup
-
// (e.g. an additional map storing sub classes of super classes: Class -> List<Class>).
-
Set<
Map.
Entry<
Class<?>,
Object>> entries = stickyEvents.
entrySet();
-
for (
Map.
Entry<
Class<?>,
Object> entry : entries) {
-
Class<?> candidateEventType = entry.
getKey();
-
if (eventType.
isAssignableFrom(candidateEventType)) {
-
Object stickyEvent = entry.
getValue();
-
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
-
}
-
}
-
}
else {
-
Object stickyEvent = stickyEvents.
get(eventType);
-
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
-
}
-
}
-
}
2.3 事件的发送
-
/** Posts the given event to the event bus. */
-
public void post(Object event) {
-
// PostingThreadState 保存着事件队列和线程状态信息
-
PostingThreadState postingState = currentPostingThreadState.
get();
-
// 获取事件队列,并将当前事件插入事件队列
-
List<Object> eventQueue = postingState.eventQueue;
-
eventQueue.
add(
event);
-
-
if (!postingState.isPosting) {
-
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
-
postingState.isPosting =
true;
-
if (postingState.canceled) {
-
throw
new EventBusException(
"Internal error. Abort state was not reset");
-
}
-
try {
-
// 处理队列中的所有事件
-
while (!eventQueue.isEmpty()) {
-
postSingleEvent(eventQueue.
remove(
0), postingState);
-
}
-
}
finally {
-
postingState.isPosting =
false;
-
postingState.isMainThread =
false;
-
}
-
}
-
}
-
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
-
Class<?> eventClass =
event.getClass();
-
boolean subscriptionFound =
false;
-
// eventInheritance 表示是否向上查找事件的父类,默认为true
-
if (eventInheritance) {
-
//获取所有事件并存放在List中,这里表示事件存在继承关系,向上查找事件的父类
-
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
-
int countTypes = eventTypes.size();
-
for (
int h =
0; h < countTypes; h++) {
-
Class<?> clazz = eventTypes.
get(h);
-
subscriptionFound |= postSingleEventForEventType(
event, postingState, clazz);
-
}
-
}
else {
-
subscriptionFound = postSingleEventForEventType(
event, postingState, eventClass);
-
}
-
// 找不到该事件时的异常处理
-
if (!subscriptionFound) {
-
if (logNoSubscriberMessages) {
-
Log.d(TAG,
"No subscribers registered for event " + eventClass);
-
}
-
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.
class &&
-
eventClass != SubscriberExceptionEvent.
class) {
-
post(
new NoSubscriberEvent(
this,
event));
-
}
-
}
-
}
-
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
-
CopyOnWriteArrayList<Subscription> subscriptions;
-
synchronized (
this) {
-
subscriptions = subscriptionsByEventType.
get(eventClass);
// 1
-
}
-
if (subscriptions !=
null && !subscriptions.isEmpty()) {
-
for (Subscription subscription : subscriptions) {
// 2
-
postingState.
event =
event;
-
postingState.subscription = subscription;
-
boolean aborted =
false;
-
try {
-
postToSubscription(subscription,
event, postingState.isMainThread);
-
aborted = postingState.canceled;
-
}
finally {
-
postingState.
event =
null;
-
postingState.subscription =
null;
-
postingState.canceled =
false;
-
}
-
if (aborted) {
-
break;
-
}
-
}
-
return
true;
-
}
-
return
false;
-
}
-
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 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);
-
}
-
}
2.4 订阅者取消注册
取消注册则需要调用unregister方法,如下所示:
-
/** Unregisters the given subscriber from all event classes. */
-
public synchronized void unregister(Object subscriber) {
-
List<Class<?>> subscribedTypes = typesBySubscriber.
get(subscriber);
// 1
-
if (subscribedTypes !=
null) {
-
for (Class<?> eventType : subscribedTypes) {
-
unsubscribeByEventType(subscriber, eventType);
// 2
-
}
-
typesBySubscriber.
remove(subscriber);
// 3
-
}
else {
-
Log.w(TAG,
"Subscriber to unregister was not registered before: " + subscriber.getClass());
-
}
-
}
-
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
-
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
-
List<Subscription> subscriptions = subscriptionsByEventType.
get(eventType);
// 1
-
if (subscriptions !=
null) {
-
int size = subscriptions.size();
-
for (
int i =
0; i < size; i++) {
-
Subscription subscription = subscriptions.
get(i);
-
if (subscription.subscriber == subscriber) {
-
subscription.active =
false;
-
subscriptions.
remove(i);
-
i--;
-
size--;
-
}
-
}
-
}
-
}
总结
从整个EventBus的执行过程来它,他实际上就是一个典型的观察者模式。通过对事件的发布与订阅,实现了一种一对多的依赖关系,并有效的为我们事件的发送者与接收者之间进行了解耦。