介绍
简化了应用程序内各组件间、组件与后台线程间的通信。
优点:开销小,代码更优雅,发送和接收端解耦。
本地广播:麻烦,效率不高,传递的数据是实体类,需要序列化,传递成本高。
基本使用
依赖
implementation 'org.greenrobot:eventbus:3.2.0'
自定义事件类
注意:就算你只传String,int这种基础类型的数据,都必须要用javaBean,不然接收不到数据。
public class TestLog implements Parcelable {
...
}
注册事件订阅
只需要在接收端注册,发送端不用注册。
EventBus.getDefault().register(this);
发送事件
// 发送普通事件
EventBus.getDefault().post(log);
// 发送黏性事件,发送黏性事件之前注意要先取消这个事件再发送
EventBus.getDefault().removeStickyEvent(TestLog.class);
EventBus.getDefault().postSticky(log);
处理事件
threadMode最常用的就是MAIN和BACKGROUND。一个在主线程中处理一个在子线程中处理。
// 处理黏性事件
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void xxx(TestLog log) {
}
// 处理普通事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void xxx(TestLog log) {
}
取消事件订阅
EventBus.getDefault().unregister(this);
源码解析
订阅
public void register(Object subscriber) {
//获取注册的对象的类型
Class> subscriberClass = subscriber.getClass();
// 找到传进来的订阅者所有订阅方法(使用@Subscribe注解的方法)
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
// SubscriberMethod保存订阅方法的Method对象,线程模式,事件类型,优先级,是否是黏性
for (SubscriberMethod subscriberMethod : subscriberMethods) {
// 对每个订阅方法进行注册
subscribe(subscriber, subscriberMethod);
}
}
}
获取所有订阅方法
SubscriberMethodFinder#findSubscriberMethods
List findSubscriberMethods(Class> subscriberClass) {
// 从缓存读
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
// 是否忽略注解器生成的MyEventBusIndex,默认false
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
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);
return subscriberMethods;
}
}
SubscriberMethodFinder#findUsingInfo
private List findUsingInfo(Class> subscriberClass) {
// 通过FindState对象来存储找到的方法信息
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 通过FindState对象来存储找到的方法信息
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
// 如果使用了MyEventBusIndex,将会进入到这里并获取订阅方法信息
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
// 未使用MyEventBusIndex将会进入这里使用反射获取方法信息
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
SubscriberMethodFinder#findUsingReflectionInSingleClass
通过反射来获取订阅者的所有方法,并根据方法的参数,类型和注解找到订阅方法。将订阅方法的相关信息保存到findState中。
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// 获取该类中声明的所有方法
methods = findState.clazz.getDeclaredMethods();
} 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 subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
// 获取该方法的第一个参数
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");
}
}
}
订阅者的注册过程
EventBus#subscribe
维护一个map,subscriptionsByEventType,key是事件类型,value是该事件类型对应的所有订阅对象(包含订阅者和订阅方法)集合,该集合按照订阅方法的优先级排序。事件发送使用。
维护一个map,typesBySubscriber,key是订阅者,value是该订阅者对应的所有事件类型集合。在反注册时可以使用。
处理黏性事件。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
// 将订阅者和订阅方法封装成一个Subscription对象
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 获取该事件类型对应的订阅对象的集合
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;
}
}
// 获取该订阅者对应的所有事件类型
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// 黏性事件,取出该事件类型对应的事件发送给当前订阅者
if (subscriberMethod.sticky) {
if (eventInheritance) {
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 {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
总结
通过反射来获取订阅者的所有方法,并根据方法的参数,类型和注解找到订阅方法集合。遍历订阅方法集合完成订阅者注册。处理黏性事件,取出黏性事件发送给对应的订阅者。
事件发送
post
EventBus#post
public void post(Object event) {
// 保存事件队列和线程状态信息
// currentPostingThreadState是一个ThreadLocal类型的变量,其中存储了对应于当前线程对应的事件列表和线程的状态信息等
PostingThreadState postingState = currentPostingThreadState.get();
// 获取事件集合,将当前事件插入事件集合中
List
EventBus#postSingleEvent
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
// 这里向上查找该事件的所有父类,默认true
if (eventInheritance) {
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 {
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));
}
}
}
EventBus#postSingleEventForEventType
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;
}
EventBus#postToSubscription
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
// 提交事件的线程是主线程,通过反射直接运行订阅的方法。
// 若不是主线程,需要把订阅事件添加到主线程队列中。通过Handler将订阅方法切换到主线程执行
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);
}
}
postSticky
整体流程同上,会多一步map缓存,key是事件类型,value是事件。
总结
获取指定线程对应的事件列表,根据事件类型,获得对应的所有订阅对象。查看当前订阅的线程和给定的threadMode是否一致,一致就通过反射直接运行订阅的方法,不一致需要将事件存储到对应线程的消息处理队列中。
要求主线程中的事件通过Handler来实现在主线程中执行,非主线程的方法会使用EventBus内部的ExecutorService来执行。
取消订阅
EventBus#unregister
public synchronized void unregister(Object subscriber) {
// 获得该订阅者所有的事件类型
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
// 删除该集合中的订阅者对应的事件类型集合
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
EventBus#unsubscribeByEventType
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
// 通过该事件类型,获得对应的订阅对象集合
List subscriptions = subscriptionsByEventType.get(eventType);
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--;
}
}
}
}
总结
订阅时维护两个集合,取消订阅清除对应的数据信息,更新集合。