前言
EventBus是Android端的一个订阅/发布的消息总线,用于Activity、Fragment、Thread、Service等应用组件的通信,并且由于事件可以是任意类型的对象,所以使用起来更加的方便快捷。
一般组件的通讯方式Intent只能实现单对单的通讯方式,而且相应的需要加以界面的跳转。
EventBus是基于观察者模式而建立的,项目中使用观察者不加以封装的话,那么就会出现各个activity/fragment层的代码接口暴增。
ps: 正常的单对单的组件通讯还是推荐使用intent,因为eventBus里面每次的通讯都会去遍历整个订阅者集合加以反射调用订阅者的订阅方法,对性能会有些影响。
本文主要从三个方面来介绍EventBus,有些功能没有涉及到,感兴趣的同学,可以自己多看看,因为到最后流程都是一样的了。
1、EventBus的注册
2、EventBus的事件发送
3、EventBus的反注册
(ps:粘性事件会在下篇文章中讲;本篇事件的接收都是以在主线程中的为例的)
一. EventBus的注册与初始化
EventBus的注册起于:EventBus.getDefault().register(Object);
EventBus.getDefault()是通过双重校验锁的方式实现了一个EventBus的单例对象,主流框架大都使用的单例,这个没有什么好说的。
在EventBus的构造方法中用了建造者模式:
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
// 初始化 第一次builder参数都为null
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
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;
}
EventBusBuilder的构造参数中我们可以看到没有入参,所以通过builder拿到的参数(大部分都是集合)要么为null,要么empty。这里有几个参数要说一下:
//
private final MainThreadSupport mainThreadSupport;
/**
*
*/
private final Poster mainThreadPoster;
/**
* 以事件类型为key,该事件对应的Subscription集合为value;
* 此处使用CopyOnWrite的好处在于它是线程安全的集合,
* 同一时间只有一个线程可以修改该集合的数据
*/
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
/**
* 订阅者对象类与其中订阅方法的事件类型对象集
*/
private final Map
mainThreadSupport是一个接口,它的实现类AndroidHandlerMainThreadSupport的构造参数是Looper类型的,而且这个Looper是主线程的Looper,在其成员方法createPoster()中会创建一个handler的对象,以下的代码可以放到后面看,但是为了能够说清楚这些参数的意义,就放到了这里
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
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) {
// Check again, this time in synchronized
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;
}
}
}
在HandlerPoster的构造方法中可以看到将looper传递给hanlder,这个looper前面说过是主线程的looper,至于为什么是主线程的后面会有说到。PendingPostQueue则是一个存储PendingPost的队列
在成员方法enqueue()中,负责创建一个PendingPost对象并放入到队列之中,然后自发一个消息用于handlerMessage接收。
最后调用 eventBus.invokeSubscriber(pendingPost)回调订阅方法[~1]
回到EventBusBuilder的创建。
EventBus的入口是register():
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()从类名和方法名可以看出,通过传入订阅者对象来获取此订阅者中的订阅方法集,我们来看下:
private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>();
List findSubscriberMethods(Class> subscriberClass) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = findUsingInfo(subscriberClass);
}
// 每个订阅者中必须要有订阅方法 即注册了eventBus 就必须要有Subscriber注解
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;
}
}
第一行通过METHOD_CACHE获取key=subscriberClass的value,值的SubscriberMethod的list集合。
METHOD_CACHE是储存订阅者以及其中订阅方法的缓存集合,在下面的else方法体中,我们可以看到METHOD_CACHE put了订阅者和订阅方法集。然后返回了订阅方法集,
SubscriberMethod是什么,它里面包含了订阅方法的一些设置信息:
public class SubscriberMethod {
/**
* 订阅者中的订阅方法
*/
final Method method;
/**
* 订阅方法的线程类型
*/
final ThreadMode threadMode;
/**
* 订阅方法的事件型
*/
final Class> eventType;
final int priority;
/**
*是否是粘性事件
*/
final boolean sticky;
/** Used for efficient comparison */
String methodString;
通过一个类对象如果获取到其中的某个或者多个特殊的方法,答案肯定是用反射。
ignoreGeneratedIndex默认为false,具体作用我没有细看,如果有兴趣的话可以再研读下,但是最后都是走的同一个方法,限于篇幅的原因我这里按照默认的来。如果METHOD_CACHE里面有以订阅者对象为key的value值,就是直接返回如果没有,往下继续应该就是开始通过反射来获取订阅者中的特殊方法类型了:
/**
* 解析订阅者 并获取其中的订阅方法集
* @param subscriberClass
* @return
*/
private List findUsingInfo(Class> subscriberClass) {
// 创建findState实例
FindState findState = prepareFindState();
// 初始化findState
findState.initForSubscriber(subscriberClass);
// 正常情况下恒不为null
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
// 第一次执行else
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对象,而且我们发现基本每一行代码都有FindState的身影,当然是在解析的过程之中都会有,我们来看下:
/**
* 用以处理订阅者中的订阅方法
* 将订阅者中的所有订阅方法储存起来
* 如果有多个订阅方法 则通过订阅方法对象、方法名称、事件类型、订阅者对象进行对比筛选
*/
static class FindState {
/**
* 订阅者中的注册的方法集
*/
final List subscriberMethods = new ArrayList<>();
/**
*订阅者中注册的方法集
* 用以判断订阅者中的订阅方法是否有订阅方法名称事件类型一样的订阅方法
*/
final Map anyMethodByEventType = new HashMap<>();
/**
* 以方法名和事件类型名为key的 订阅者对象类为value
* 订阅者中有多个订阅方法时 通过key获取value 如果 新旧value一样则不添加并将老value重新放入集合中
*/
final Map subscriberClassByMethodKey = new HashMap<>();
/**
* 放置订阅方法的方法名和入参对象名称
*/
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class> subscriberClass;
Class> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class> subscriberClass) {
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
/**
*如果一个订阅者对象类中有多个订阅对象
* @param method 传入待判断的方法类
* @param eventType 事件类型
* @return
*/
boolean checkAdd(Method method, Class> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
// 以入参类型对象为key保存到集合中
// 如果存在旧值
// 并且与传入的方法类有关系 则throw
// 如果没有关系进一步检验 如果不存在直接返回true
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());
// 以方法名和事件类型名称拼接起来作为key
String methodKey = methodKeyBuilder.toString();
// 返回此方法所定义在的类对象
Class> methodClass = method.getDeclaringClass();
// subscriberClassByMethodKey通过put检查返回值 如果不为null 则将老值重新放入集合中并返回false 如果为null 则返回true
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. */
// 如果使用eventbus则 包名不能以以下字符开头 同时 也是祛除如果订阅者的父类是java或者android的类 则clazz为null
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
注释我都有加,注意的有两点,
一个是如果当前订阅者有多个订阅方法,
如果事件类型不一致,则判断为是不同的方法。
如果事件类型一致,则将方法名与事件类型名称拼接起来作为key通过put去查找,如果subscriberClassByMethodKey集合的返回值为null的话,则判断为是不同的方法,直接返回true,
如果返回值不为null的话,将老值重新放入集合中并返回false;
另一个需要注意的是moveToSuperClass(),它会先得到订阅者的父类包名+类名,如果是以java. javax.android.开头的直接设置clazz = null;
总结一下,这个FindState的作用就是判断订阅者中是否有两个方法名称、事件类型一致的订阅方法。
我们来看findUsingReflectionSingleClass(FindState):
/**
* 解析订阅方法
* @param 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();
} 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];
// 第一次进入返回true 重复注册返回false
if (findState.checkAdd(method, eventType)) {
// 获取注解里面的设置的接收事件的线程
ThreadMode threadMode = subscribeAnnotation.threadMode();
// priority代表注解里面的设置的事件的优先级 sticky代表注解里面的设置的事件是否是粘性事件 boolean 类型 默认为false
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中的subsriberMethods中,到这里发现原来FindState的作用不止是校验注册的订阅方法的合理性,还将订阅方法储存了起来。
在findUseingInfo中最终返回了getMethodsAndRelease(FindState),现在已经拿到了订阅者的方法为什么还要走这一步呢,直接返回了findState.subscriberMethods 不就好了么
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
/**
* 返回订阅者中的订阅方法集
* @param findState
* @return
*/
private List getMethodsAndRelease(FindState findState) {
List subscriberMethods = new ArrayList<>(findState.subscriberMethods);
// 清空findState对象
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
我们可以看到原来是将刚刚获取到的FindState对象放到了一个静态集合当中,
说到这里我们来看下前面在实例化FindState的方法prepareFindState()
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
两个方法结合起来就是,
实例化的时候,如果集合当中有FindState对象,则直接返回,并将数组的当前下标置为null,如果没有则new一个;
将FindState放入到数组的时候,如果如果为null则直接放入。
这么做的结果就是数组当中永远只保持着一个FindState对象,至于原因么,我也不清楚,呵呵...
到这里,整个register()走了一半,就是获取订阅者中的订阅方法集。
回到register():
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
// 返回注册的订阅者中的订阅方法集
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
// 遍历循环处理订阅者中的订阅方法
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
现在我们已经拿到了订阅者的方法集,
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
// 获取订阅方法的事件类型
Class> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
/**
* 通过订阅者中的订阅方法集 正常为情况下为null 如果多次注册 或者是在activity退出的时候没有反注册 就会报错
* 并将订阅者与其中的订阅方法集储存起来
*/
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) {
// 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 {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
抛开粘性事件不说,这里主要为两个集合添加了值,一个是subscriptionsByEventType,以事件类型为key,订阅方法集为value的集合,另一个是以订阅者为key,事件类型为value的集合
到这里register完全结束,大致流程就是根据订阅者获取其中的订阅方法集,以及其中的事件类型 并保存下来
二、EvnentBus 事件的发送
/**
* 发送事件
* @param event
*/
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
// 获取事件对象集 并将要发送的事件放入集合中
List
PostingThreadState 是由ThreadLocal维护,线程独立的,这里将要发送的事件放入到PostingThreadState 的eventQueue集合中,然后遍历删除并将index=0的event和postiongState传给postSingleEvent();
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
// eventInheritance 默认为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));
}
}
}
eventInheriteance是在EventBuilder中赋值的 默认为true
/**
* 在所有父类和接口中查找所有入参类型对象
* @param eventClass
* @return
*/
private static List> lookupAllEventTypes(Class> eventClass) {
synchronized (eventTypesCache) {
List> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class> clazz = eventClass;
while (clazz != null) {
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
/**
* 将事件对象的父类以及接口加入集合中
* @param eventTypes
* @param interfaces
*/
static void addInterfaces(List> eventTypes, Class>[] interfaces) {
for (Class> interfaceClass : interfaces) {
if (!eventTypes.contains(interfaceClass)) {
eventTypes.add(interfaceClass);
addInterfaces(eventTypes, interfaceClass.getInterfaces());
}
}
}
这里是将事件对象的所有父类和实现的接口对象放入集合当中,并缓存到eventTypesCache当中;
我们拿到事件类型以及其对应的父类、接口对象集之后
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;
}
这个方法里,首先获取到事件类型所对应的Subscription集合,Subscription里面是订阅者对象以及订阅方法
到这里我们应该想到下面的流程大致就是 根据事件类型 将事件发送到事件对应的每一个订阅者对象里面,表现为调用这个订阅者里面的订阅方法,继续往下看:
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);
}
}
这里用以判断要接受的线程类型。这里以MAIN为例,如果当前是主线程,则直接发送事件
/**
* 通过代理回调订阅者的订阅方法
* @param subscription
* @param event
*/
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
通过代理调用订阅者的订阅方法
如果发送线程不是主线程,会通过mainThreadPoster.enqueue(), mainThreadPoster在前面我们说过,他是一个在主线程接收消息的handler,最后调用eventBus.invokeSubscriber(pendingPost),在主线程中将事件发送出去。
前面有一个问题,说为什么会是主线程,看下图:
三、反注册
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());
}
}
typesBySubscriber是以订阅者为key,订阅者里面所有的事件类型为value的集合,这里通过订阅者获取到其中的所有事件类型,然后循环调用unsubscribeByEventType,并将此订阅者从集合中remove掉
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--;
}
}
}
}
subscriptionsByEventType是以事件类型为key,以Subscription类型的list集合为value的集合,Subscription里面包含着订阅方法与其所对应的订阅者,还有一个boolean类型的标识着此订阅者是否被反注册了
final Object subscriber;
final SubscriberMethod subscriberMethod;
/**
* Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
* {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
*/
volatile boolean active;
在unsubscribeByEventType方法中我们可以看到是循环遍历删除subscriptionsByEventType中的以取消订阅的订阅者中的事件类型所对应的对象,这里有一个subscription.active = false代表此事件被反注册,具体应用的地方我们以在主线程接收事件为例:
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
如果时间没有被反注册 就是去动态代理调用订阅者的订阅方法,这个方法在我们前面说过的那个handler的子类中调用:
@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) {
// Check again, this time in synchronized
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;
}
}
在handlerMessage中调用