一、类定义
- 为了更好的说明问题,在介绍EventBus源码以及机制之前,我们先定义两个类:
EventClass
,SubscriberClass
分别泛指用户自定义的事件类和事件的订阅者,eventObject
,subscriberObject
分别泛指订阅者和被订阅事件的实例。
EventClass
类
public class EventClass {
private String message;
public EventClass() {
}
public EventClass(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
复制代码
SubscriberClass
类
public class SubscriberClass {
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void onMessageEvent(EventClass eventObject) {
Log.e("MessageSubscriber", "onMessageEvent1:" + eventObject.getMessage());
}
@Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 2,sticky = true)
public void onMessageEvent3(EventClass eventObject) {
Log.e("MessageSubscriber", "onMessageEvent3:" + eventObject.getMessage());
}
@Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 10,sticky = true)
public void onMessageEvent4(EventClass eventObject) {
Log.e("MessageSubscriber", "onMessageEvent4:" + eventObject.getMessage());
}
@Subscribe(threadMode = ThreadMode.ASYNC, priority = 100,sticky = true)
public void onMessageEvent5(EventClass eventObject) {
Log.e("MessageSubscriber", "onMessageEvent5:" + eventObject.getMessage());
}
}
复制代码
二、使用方式:
- 订阅者注册,事件触发
1.注册订阅者:
SubscriberClass subscriberObject = new SubscriberClass();
EventBus.getDefault().register(subscriberObject);
复制代码
2.触发事件:
EventBus.getDefault().post(new EventClass("Hello World"));
复制代码
3.接收事件: 事件被post出后,就可以在subscriberObject
对象的各个参数为EventClass
方法中接收到了。可见subscriberObject
在使用方法上非常像接口对象,等待被回调。
三、EventBus类:
- 在我们了解EventBus的订阅,触发逻辑之前,我们先来了解一下
EventBus
类
EventBus类中的关键属性:
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
private final Map
1.subscriptionsByEventType
-
key:eventObject的Class;value:一个线程安全的Subscription列表。 我们先来了解一下
Subscription
类:Subscription
final Object subscriber; // 注册EventBus事件接收者的对象。即我们上面定义的subscribeObject;显然一个Subscription的粒度是订阅者对象级别,而不是类级别。 final SubscriberMethod subscriberMethod; // 一个事件捕捉者的封装类对象 复制代码
SubscriberMethod
final Method method; // 捕捉事件的方法即 subcribeObject的某个参数类型为eventType的method final ThreadMode threadMode; // 从方法注解中解析出的方法的相关描述信息:线程模型 final Class eventType; // 方法的参数类型,即上文定义的eventObject的参数类。 final int priority; // 事件优先级 final boolean sticky; // 是否是stickEvent String methodString; // 相当于一个方法的标签,用于比较是否相同 复制代码
由以上代码以及注释可见:
Subscription
是一个事件的执行单元。因此 EventBus的属性**subscriptionsByEventType
**的作用非常关键,当post eventObject时,会根据eventObject的类型通过 subscriptionsByEventType.get(eventObject.getClass())获取到一个Subscription,使用Subscription通过反射调用subscribeObject的相关方法,从而使订阅者接收到事件。当然具体的调用过程略复杂,我们稍后讲解。
2.typesBySubscriber
- key:观察者subscribeObject; value:subscribeObject类的所有被观察者(eventObject)的Class。 typesBySubscriber主要在unregist的过程中起作用(regist时生成和更新),unregist时,根据订阅者(subscribeObject)的类型(key),找到所有被订阅事件(eventObject)的类型List,根据事件类型在
subscriptionsByEventType
中找到所有观察者Subscriptions,如果Subscription的执行者是subscribeObject,则移除(因为显然一个Subscription是订阅者对象级别,而非类级别)。所以typesBySubscriber
只起到记录作用。
3.stickyEvents
- key:被观察者(事件)类型;value:被观察者(事件对象)。可见,相同的事件类型只会存储最近一次发送的事件。
4.currentPostingThreadState
- 场景: 存储当前线程的事件发送状况。当post一个事件,如果当前线程正在post事件则会进入post事件池,否则while循环从事件池不断取出事件,调用
postSingleEvent(Object event, PostingThreadState postingState)
方法,找到所有订阅者类名。分别调用postSingleEventForEventType(Object event, PostingThreadState postingState, Class eventClass)
调用‘subscriptionsByEventType.get()’获取所有当前事件的Subscription,-
**
PostingThreadState
**类:final static class PostingThreadState { final List
-
5.subscriberMethodFinder
SubscriberMethodFinder
类对象 对外只提供了findSubscriberMethods方法。此类的作用是通过subscribeObject对象的类型,找到此类中所有的事件接收方法。封装成List。在EventBus类的逻辑用于生成和更新subscriptionsByEventType
和typesBySubscriber
。具体组装逻辑在后面章节讲解,此类也是EventBus2.x和EventBus3.x的主要区别。
6.标记性属性:以下EventBus中的标记性属性比较简单
private final boolean throwSubscriberException; // 在反射调用subscriberObject中的方法失败时是否抛出异常
private final boolean logSubscriberExceptions; // 在反射调用subscriberObject中的方法失败时是否打印log
private final boolean logNoSubscriberMessages; // post的eventObject无订阅者时是否打印log
private final boolean sendSubscriberExceptionEvent; // 在反射调用subscriberObject中的方法失败时是否post出SubscriberExceptionEvent事件,用户可以像订阅普通事件一样订阅SubscriberExceptionEvent
private final boolean sendNoSubscriberEvent; // post的eventObject无订阅者时是否post NoSubscriberEvent...
private final boolean eventInheritance; // post的evntObject是否触发父类对象订阅者,默认为true
private final int indexCount; // 注解生成类数量,没有实际用处。
private final Logger logger;
复制代码
7.当然还有各类事件执行器。
private final Poster mainThreadPoster; // 实际是 AndroidHandlerMainThreadSupport实例,规定了Looper为MainThreadLooper的HandlerPoster
private final BackgroundPoster backgroundPoster;
private final AsyncPoster asyncPoster;
private final ExecutorService executorService;
复制代码
根据subscribeObject--> Subscription--> SubscriberMethod--> Method 的注解,ThreadMode,分别使用不同方式在不同线程触发事件。这也是EventBus在各线程中进行穿插传递的原因。 并且AsyncPoster,BackgroundPoster,SubscriberPoster这些事件执行器都是在EventBusBuilder中初始化的Executors.newCachedThreadPool();
四、 EventBus3.0 事件机制
OK 分析完EventBus类中的基本属性之后,更详细的分析EventBus的事件机制,包括订阅者注册和事件触发两部分。
1.register源码分析:
EventBus3.0 订阅者注册的过程,实际为EventBus中的两个重要属性subscriptionsByEventType
typesBySubscriber
的组织构造过程。 EventBus3.0 之后提供了AnnnationProcessor机制,替换掉了一部分需要使用反射的地方(事件注册部分),大大提高了性能。但是在事件触发阶段依然会用到反射。
public void register(Object subscriber) {
Class subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
复制代码
可见,注册的过程中通过subscriberMethodFinder找到注册对象的类中所有接收事件的方法封装成List
, subscribe方法分别注册。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class eventType = subscriberMethod.eventType;
// 填充subscriptionsByEventType
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); //-- 可见同一个对象,在unregist之前只能注册一次。
}
}
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;
}
}
// subscriptionsByEventType填充结束,开始填充typesBySubscriber
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// typesBySubscriber 填充结束,针对stickEvent特殊处理:
if (subscriberMethod.sticky) {
// 如果当前的subscriberMethod封装的是接收sitckEvent的方法
if (eventInheritance) {
// 如果发送父类事件,默认为true
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);
}
}
}
复制代码
由源码可见,subscribe的过程,就是在EventBus中填充subscriptionsByEventType
和typesBySubscriber
的过程,这两个属性的作用我们已经在上文讲解。同时,会有针对stickEvent的特别处理,代码注释中已经说明。
至此,事件注册的流程已经讲解清楚,接下来重点讲解一下**SubscriberMethodFinder
**类,如何通过一个对象找到当前对象所有订阅事件的方法并封装成List
。
SubscriberMethodFinder
类重要属性:
private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>();
private List subscriberInfoIndexes;
private final boolean strictMethodVerification;
private final boolean ignoreGeneratedIndex;
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
复制代码
METHOD_CACHE
: key:subScirbeObject的类型,value,此订阅者类型中的订阅者方法列表。subscriberInfoIndexes
: 通过AnnnationProcessor自动生成的SubscriberInfoIndex
子类对象列表。我们在使用EventBus3.0时用EventBus.builder().addIndex(SubscriberInfoIndex index)
的方式添加。strictMethodVerification
: 可通过EventBusBuilder中设置,默认为false,使用严格的方法验证。当设置为true时,如果订阅者类中使用@Subscribe
注解的方法,参数个数不等于1,或者方法类型非法(@Subscribe method: must be public, non-static, and non-abstract)时抛出EventBusException.ignoreGeneratedIndex
: 可通过EventBusBuilder中设置,是否忽略AnnnationProcessor自动生成的SubscriberInfoIndex子类,默认为false。不忽略。否则完全使用反射的方法。FIND_STATE_POOL
: FindState享元池
SubscriberMethodFinder
类构造函数
SubscriberMethodFinder(List subscriberInfoIndexes, boolean strictMethodVerification,
boolean ignoreGeneratedIndex) {
this.subscriberInfoIndexes = subscriberInfoIndexes;
this.strictMethodVerification = strictMethodVerification;
this.ignoreGeneratedIndex = ignoreGeneratedIndex;
}
复制代码
在EventBus的构造函数中创建,前面已经讲解,subscriberMethodFinder
是EventBus类的重要属性。
List findSubscriberMethods(Class subscriberClass) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
// 忽略通过AnnnationProcessor自动生成的`SubscriberInfoIndex`子类,完全使用反射实现。
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 使用SubscriberInfoIndex
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//- 将subscriberMethods写入缓存。
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
复制代码
findSubscriberMethods
方法是SubscriberMethodFinder
类唯一对外暴露的方法,参数为订阅者方法类型,返回值为此订阅类中的所有事件接受者方法(即使用了@Subscriber注解的方法),并将方法封装为SubscriberMethod
。SubscriberMethod
类前面已经讲解。
private List findUsingInfo(Class subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
复制代码
FindState
类是SubscriberMethodFinder
类的内部静态类。EventBus3.0 在用FindState类时,使用了享元模式,构造了一个FIND_STATE_POOL
,默认存储4个。如果四个被同时占用则新创建一个。prepareFindState()的过程便是从池中获取或者new FindState。进入FindState类,看一下FindState
类都做了什么。
static class FindState {
// 当前订阅类以及其父类订阅事件的方法封装为SubscriberMethod的集合
final List subscriberMethods = new ArrayList<>();
final Map anyMethodByEventType = new HashMap<>();
final Map subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
// 当前订阅类
Class subscriberClass;
// 当前搜索的类,可能为订阅类或者其父类
Class clazz;
// 是否不发送父类的方法
boolean skipSuperClasses;
// 通过EventBusBuilder传过来的Index,调用getSubscriberInfo()来初始化;
SubscriberInfo subscriberInfo;
// 通过订阅者类初始化
void initForSubscriber(Class subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
// 清除数据,备 FIND_STATE_POOL回收。
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
boolean checkAdd(Method method, Class eventType) {
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
private boolean checkAddWithMethodSignature(Method method, Class eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class methodClass = method.getDeclaringClass();
Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
复制代码
几个类的继承关系: interface SubscriberInfo
--> abstract class AbstractSubscriberInfo
--> class SimpleSubscriberInfo
public interface SubscriberInfo {
Class getSubscriberClass();
SubscriberMethod[] getSubscriberMethods();
SubscriberInfo getSuperSubscriberInfo();
boolean shouldCheckSuperclass();
}
复制代码
interface SubscriberInfoIndex
--> 自动生成的类 class MyEventBusIndex
public interface SubscriberInfoIndex {
SubscriberInfo getSubscriberInfo(Class subscriberClass);
}
复制代码
AnnnationProcessor的作用便是在编译阶段,通过解析代码注解,生成MyEventBusIndex类,生成静态Map
,提供getSubscriberInfo方法的实现,可以根据订阅者类型返回SimpleSubscriberInfo。看一下SimpleSubscriberInfo
源码:
public class SimpleSubscriberInfo extends AbstractSubscriberInfo {
private final SubscriberMethodInfo[] methodInfos;
public SimpleSubscriberInfo(Class subscriberClass, boolean shouldCheckSuperclass, SubscriberMethodInfo[] methodInfos) {
super(subscriberClass, null, shouldCheckSuperclass);
this.methodInfos = methodInfos;
}
@Override
public synchronized SubscriberMethod[] getSubscriberMethods() {
int length = methodInfos.length;
SubscriberMethod[] methods = new SubscriberMethod[length];
for (int i = 0; i < length; i++) {
SubscriberMethodInfo info = methodInfos[i];
methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,
info.priority, info.sticky);
}
return methods;
}
}
复制代码
可以看到SimpleSubscriberInfo
的构造函数中有一个参数methodInfos,类型为SubscriberMethodInfo
,为什么不是SubscriberMethod
呢?看一下SubscriberMethodInfo
的源码:
public class SubscriberMethodInfo {
final String methodName;
final ThreadMode threadMode;
final Class eventType;
final int priority;
final boolean sticky;
}
复制代码
可见SubscriberMethod
在编译期的过渡类:SubscriberMethodInfo
,之所以称它为过渡类,因为显然在编译阶段SubscriberMethod
类的method
字段在编译期不可能被生成。只有在运行时通过反射获取。在getSubscriberMethods
方法中完成了这部分转化。方法中调用了createSubscriberMethod
,方法在父类AbstractSubscriberInfo
中实现:
protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode,
int priority, boolean sticky) {
try {
// 在运行时通过反射得到Method,封装成SubscriberMethod
Method method = subscriberClass.getDeclaredMethod(methodName, eventType);
return new SubscriberMethod(method, eventType, threadMode, priority, sticky);
} catch (NoSuchMethodException e) {
throw new EventBusException("Could not find subscriber method in " + subscriberClass +
". Maybe a missing ProGuard rule?", e);
}
}
复制代码
正如我们分析的,method字段是在运行时(精确来讲是事件注册时)通过反射得到。
ok,以上是EventBus3.0,当使用AnnationProcessor时的注册流程,在不使用AnnationProcessor或者根据自动生成类找不到相关订阅方法类时,使用反射的方法完成注册。
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();
} 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");
}
}
}
复制代码
这些代码比较简单,根据FindState中存储的类名,遍历该类下的方法,过滤EventBus3.0不支持的方法类型。根据注解将方法封装成一个个SubscriberMethod。最终效果与使用AnnationProcessor相同得到List
。
至此,SubscriberMethodFinder
类已经分析完成。简单来讲,SubscriberMethodFinder
类的作用便是根据订阅者的类型找到一系列订阅者方法并封装为List
。
2. unregister源码分析:
public synchronized void unregister(Object subscriber) {
// 通过typesBySubscriber找到订阅者订阅的所有事件类型类
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class eventType : subscribedTypes) {
// 根据订阅者和事件类型,清除subscribeByEventType中相关存储
unsubscribeByEventType(subscriber, eventType);
}
// 将事件订阅者从typesBySubscriber中移除
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
复制代码
private void unsubscribeByEventType(Object subscriber, Class eventType) {
// 找到当前事件类型的所有 Subscription,如果Subscription对应的object是当前subscriber则将活跃性设置为false,并从subscriptionsByEventType中移除
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--;
}
}
}
}
复制代码
由源码可见,EventBus的unregister过程,便是EventBus类中typesBySubscriber
和subscriptionsByEventType
清除订阅者的过程。
3. 事件触发源码分析:
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List
currentPostingThreadState
我们上文已经分析。post(Object event)时,首先获取当前线程的事件发送状态postingState,将event存入eventQuene。如果isPosting==false,则循环从eventQuene中取出消息,执行postSingleEvent方法。(由于postingState存储于ThreadLocal中,每个线程获取的postingState都是不同的,然而同一个线程中的代码是顺序执行的,所以怎么会遇到postingState.isPosting==true的情况呢,不知道为什么EventBus会使用eventQuene,并加这样的判断。对此可以给出合理解释的同学欢迎联系我,虚心求教,EventBus官方给出的解释是他们对ThreadLocal机制不太了解)。
进入postSingleEvent方法。
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class eventClass = event.getClass();
boolean subscriptionFound = false;
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));
}
}
}
复制代码
可见,postSingleEvent方法中通过eventInheritance
(上文已经分析)做判断是否触发订阅了事件父类事件类型的订阅者接收,eventInheritance
默认为true,找到所有父类已经接口类,进入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;
}
复制代码
postSingleEventForEventType
方法中通过subscriptionsByEventType
属性获取所有订阅了当前事件类型的订阅者封装对象subscriptions
,for循环递归处理事件分发,首先填充postingState
部分字段,可见postingState
在post的过程中起上下文的作用。之后调用方法postToSubscription()
。
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
if (event instanceof MultiProcessSerializeEvent && ((MultiProcessSerializeEvent) event).isSendToCenter()) {
if (subscription.subscriberMethod.threadMode == ThreadMode.MULTI_PROCESS)
processPoster.enqueue(subscription, event);
return;
}
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 {
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);
}
}
复制代码
由源码可见,postToSubscription
方法中根据subscription
中的Method的threadMode
的不同,即接收者线程的不同,使用不同的Poster进行处理。
ThreadMode.POSTING
:在事件触发线程执行事件:
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
复制代码
非常简单,直接使用反射,执行订阅者对象的订阅方法。
ThreadMode.MAIN
: 判断当前线程如果为主线程则直接反射调用,否则mainThreadPoster处理,mainThreadPoster实际上是一个HandlerPoster,分析一下HandlerPoster的源码:
public class HandlerPoster extends Handler implements Poster {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
复制代码
EventBus类中的invokeSubscriber
:
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
// 显然PendingPost也使用了享元模式
PendingPost.releasePendingPost(pendingPost);
// 是否已经unregister判断
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
复制代码
显然代码很简单,只不过一个包含了消息队列PendingPostQueue的Handler, enqueue时将消息存入消息队列,同时触犯sendMessage,在handleMessage()中循环遍历消息队列,将事件取出, 发给EventBus通过反射调用。由于Handler的handleMessage()执行于Looper的创建线程,而HandlerPoster
创建时使用的Looper正式Looper.mainLooper()得到,所以保证了hreadMode.MAIN
在主线程触发。
ThreadMode.MAIN_ORDERED
: 大体与ThreadMode.MAIN
相同,不过优先进入mainThreadPoster
队列。这很大程度上保证了订阅者接收事件的顺序与发送事件的顺序相同。ThreadMode.BACKGROUND
:
final class BackgroundPoster implements Runnable, Poster {
private final PendingPostQueue queue;
private final EventBus eventBus;
private volatile boolean executorRunning;
BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
复制代码
如果当前线程为非MAIN线程则直接调通过反射调用,否则使用BackgroundPoster
的实例发送事件,其实与HandlerPoster
并没有太大差异,不过是一个Runnable,执行在Executors.newCachedThreadPool()线程池。保证一定会在异步线程执行。但是值得注意的是,既然已经使用了线程池,为什么还要使用PendingPostQueue呢?显然通过源码我们可以知道,在enqueue时如果有正在处理的事件则将事件写入PendingPostQueue,run()时再从quene中取出,这样做的作用是尽量保证事件执行的顺序。同样这也造成了,如果使用ThreadMode.BACKGROUND
执行很耗时的后台操作,可能会造成后台任务阻塞(等待前面的任务执行完成)。
ThreadMode.ASYNC
:
ThreadMode.ASYNC
使用的AysncPoster
与BackgroundPoster
大体相同,并且同样使用了Executors.newCachedThreadPool()线程池,但是抛弃了PendingPostQueue,而且所有执行的信任都会在线程池中直接执行。所以ThreadMode.ASYNC
模式适合耗时的异步任务。不会造成后台线程阻塞。
至此EventBus3.0源码已经完全分析完成。
五、修改EventBus3.0 支持多进程通讯
- EventBus3.0 并没有提供任何跨进程的处理方案。我们修改一下,添加一种事件模式ThreadMode.MULTI_PROCESS。