简介
EventBus是一种可用于Android或者Java程序的发布/订阅事件总线。它能简化Activities, Fragments, Threads, Services等组件之间的通信。用更少的代码,达到更高的质量。
它有很多优点:
简化应用组件间的通信;
解耦事件的发送者和接收者;
避免复杂和容易出错的依赖和生命周期的问题;
很快,专门为高性能优化过等等。
使用方法
- 创建事件
EventBus3.0以后,创建的事件可以是任何类。
public static class MessageEvent {
/* Additional fields if needed */
}
- 订阅者准备事件处理函数
EventBus3.0以后,事件处理函数的函数名可以任意命名,但是函数必须用Subscribe注释,还可以在Subscribe注释中指定ThreadMode,priority,sticky。
ThreadMode 表示事件的处理方式,是同步还是异步处理,是在发布者同一线程还是另起一个线程。
priority表示优先级,priority值越大越推后执行。
sticky表示本事件处理函数可以用于处理sticky事件,在订阅者注册的时候,sticky事件会被投递给订阅者处理。
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
/* Do something */
};
- 订阅者注册
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
- 发布者post事件
EventBus.getDefault().post(new MessageEvent());
代码流程分析
- EventBus单件模式
EventBus实例在单个进程内是独一无二的,每个线程都可以引用。
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
- 注册流程
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
注册函数首先调用subscriberMethodFinder.findSubscriberMethods(subscriberClass) 来取得这个类所有的事件处理函数。
然后对每个SubscriberMethod ,循环调用subscribe。
subscribe函数主要完成三件事:
- 把新的Subscription添加到对应eventType的Subscription列表中 subscriptionsByEventType
- 把eventType添加到对应subscriber的subscribedEvents列表中 typesBySubscriber
- 如果订阅者的事件处理函数有sticky标记的,则把系统中对应的sticky事件派发给订阅者
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//1 把新的Subscription添加到对应eventType的Subscription列表中
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
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);
break;
}
}
//2 把eventType添加到对应subscriber的subscribedEvents列表中
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//3 把系统中对应的sticky事件派发给订阅者
if (subscriberMethod.sticky) {
if (eventInheritance) {//如果eventInheritance true 即事件处理函数会处理事件及派生类事件
// 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).
Set, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, Object> entry : entries) {
Class> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {//如果eventInheritance false 即事件处理函数不处理派生类事件
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
- post流程
在post流程,发布者把事件派发出去,交给相应的线程,由对应的事件处理函数处理。
post流程的主要步骤:
- 把事件加入发布者线程的待投递事件队列
- 把待投递事件队列的所有事件按照先入先出的顺序全部派发出去
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get(); //获取发布者线程的私有数据
List
具体的派发流程在postSingleEvent中实现
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) { //如果eventInheritance为true,把event事件以及父类事件全部派发
List> 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 {//如果eventInheritance为false,只把event事件派发
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
在postSingleEventForEventType中,把event派发给对应的订阅者
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
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;
}
真正的派发是在postToSubscription中进行的。派发时,根据事件处理函数注释中的threadMode,采取不同的派发策略。
POSTING:
POSTING订阅者 ,则立即执行事件处理函数。
MAIN:
MAIN订阅者,如果发布者在主线程,则立即执行事件处理函数。
如果发布者不在主线程,则派发到mainThreadPoster异步执行,但是执行线程仍然是主线程。
MAIN_ORDERED:
MAIN_ORDERED订阅者,对于android平台来说,是统一派发到mainThreadPoster异步执行的。其他平台,则是立即执行。
BACKGROUND:如果发布者在主线程,则派发到backgroundPoster异步执行。backgroundPoster会把事件放到线程池中处理。如果不在主线程,则立即执行。
ASYNC:统一派发到asyncPoster中异步执行。asyncPoster会把事件放到线程池中处理。
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);
}
}