上一篇文章记录了EventBus的基本使用,这一篇文章我们深入EventBus源码进行学习
1.EventBus构造方法
getDefault()方法
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();//构造方法
}
}
}
return defaultInstance;
}
很明显这里是一个单例模式,使用的是DCL双检查机制,具体单例设计模式相关知识可以查看我的Android面向面试复习-Java篇进行学习,接下来,我们点进EventBus构造方法进行查看
EventBus()构造方法
public EventBus() {
this(DEFAULT_BUILDER);
}
点进DEFAULT_BUILDER后发现是默认的EventBusBuilder
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
我们点击this后发现其中有HashMap和ConcurrentHashMap这样的数据结构用于存储信息,这里采用的是建造者模式,通过构造一个EventBusBuilder来对EventBus进行配置
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
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;
}
2. 订阅者注册
2.1 查找订阅者的订阅方法
register()方法
获取EventBus后便可将订阅者注册到EventBus
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
上面代码第3行的findSubscriberMethods()用于找出一个SubscriberMethod集合,也就是传进来的订阅者的所有订阅方法,接下来在同步块中进行遍历订阅者的订阅方法完成订阅者的注册操作。由此看出register()方法做了两件事:
- 查找订阅者的订阅方法
- 完成订阅者的注册
在List<>集合中的SubscriberMethod类主要保存了订阅方法的Method对象、线程模式、事件类型、优先级、是否是黏性事件等属性
接下来我们就来看看findSubscriberMethods()方法
findSubscriberMethods()方法
List findSubscriberMethods(Class> subscriberClass) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
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;
}
}
上面代码第2行的METHOD_CACHE表示从缓存中查找是否有订阅方法的集合,如果找到了,即第3行subscriberMethods != null,立刻return返回。如果没找到,则根据ignoreGeneratedIndex属性的值来选择用何种方法来查找订阅方法的集合(ignoreGeneratedIndex表示是否忽略注解器生成的MyEventBusIndex)。ignoreGeneratedIndex默认值为false,可以通过EventBusBuilder来设置。
上面代码倒数第4行即最后一个else块中,找到订阅方法的集合就put()放入缓存,避免下次继续查找。我们在项目中经常使用EventBus单例模式来获取默认的EventBus对象,即ignoreGeneratedIndex为false的情况,这种情况调用上面代码第1个else块中的findUsingInfo方法,下面我们来看看这个方法做了什么
findUsingInfo()方法
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);
}
上面代码中while()循环里第一行代码通过getSubscriberInfo方法获取订阅者信息,在我们查找订阅方法的时候并没有忽略注解器为我们生成的索引MyEventBusIndex,如果我们通过EVentBusBuilder配置了EventBusIndex,便会获取subscriberInfo。
上面代码第一个if里就通过subscriberInfo的getSubscriberMethods()方法便可以得到订阅方法的相关信息。如果没有配置MyEventBusIndex,便会执行第一个else块中的findUsingReflectionInSingleClass()方法,将订阅方法保存在findState中,最后通过getMethodsAndRelease方法对findState做回收处理并返回订阅方法的List<>集合。
由于默认情况是没有配置MyEventBusIndex的,所以我们现在看一下findUsingReflectionInSingleClass()方法做了什么
findUsingReflectionInSingleClass()方法
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");
}
}
}
这段代码比较长,但我们只需要看第一个try/catch中使用反射来获取订阅者中的所有方法,并根据方法的类型、参数、注解来找到订阅方法,找到订阅方法后将订阅方法的相关信息保存在findState中,即可。
2.2 订阅者的注册过程
上述几个方法已经完成了订阅者的查找方法功能,之后便开始进行注册,我们回到register()方法里看看它的subscribe()方法对订阅者的订阅方法进行了注册,也就是register()方法做的第二件事
subscribe()方法
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class> eventType = subscriberMethod.eventType;
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) {
// 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);
}
}
}
首先,我们看上面代码第3行,根据subscriber(订阅者)和subscriberMethod(订阅方法)创建了一个Subscription(订阅对象)。在第4行里通过eventType(事件类型)获取subscriptions(订阅对象)集合,如果Subscriptions为null则重新创建,并将Subscriptions根据eventType保存在subscriptionsByEventType(Map集合)。
在for循环中按照订阅方法的优先级add()插入到对象集合中,完成订阅方法的注册。
在List<>集合中通过subscriber获取subscribedEvents(事件类型集合),如果subscribedEvents == null则重新创建,并将eventType添加到subscribedEvents中,并根据subscriber将subscribedEvents存储在typesBySubscriber(Map集合)中。
如果是黏性事件,则在最后一个else块中从stickyEvents里根据eventType获取该事件类型的事件发送给当前订阅者。
由上可知subscribe()方法做了两件事:
- 将Subscription根据eventType封装到subscriptionsByEventType中,将subscribedEvents根据subscriber封装到typesBySubscriber中
- 处理黏性事件
3. 事件的发送
post()方法
获取到EventBus对象后,可以通过post方法进行对事件的提交
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List
上面代码第1行里从PostingThreadState对象中取出事件队列,然后将当前事件add()插入事件队列,在while()循环里只要队列不空,就将队列中的事件依次交由postSingleEvent方法进行处理,并remove()移除该事件,下面查看postSingleEvent()方法做了什么
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) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
上面代码第4行,就是第一个if块中根据eventInheritance(表示是否向上查找事件的父类,默认值为true,可以在EventBusBuilder中进行配置),通过lookupAllEventTypes()方法找到所有的父类事件并存在List<>集合里,然后在for循环里和第一个else块里通过postSingleEventForEventType()对事件进行逐一处理,下面看看postSingleEventForEventType()方法做了什么
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;
}
上面代码第3行即第一个同步块中取出该事件对应的SubScripstions(订阅对象集合),在第一个for循环中遍历Subscriptions,将事件event和对应的subscriptions(订阅对象)传递给postingState并在第一个try/finally块中调用postToSubscription方法对事件进行处理,下面看看postToSubscription()方法做了什么
postToSubscription()方法
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);
}
}
取出订阅方法的threadMode(线程模式),之后使用switch根据threadMode来分别处理,如果threadMode为MAIN,若提交事件的线程为主线程,则通过反射直接运行订阅的方法,若其不是主线程,则需要mainThreadPoster将我们的订阅事件添加到主线程队列中,mainThreadposter是HandlerPoster类型的,继承自Handler,通过Handler将订阅方法切换到主线程进行。
4. 订阅者取消注册
取消注册调用unregister()方法
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 {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
在订阅者注册中提到过typesBySubscriber,是一个Map集合,上面代码List<>集合里通过subscriber找到subscribedTypes(事件类型集合)。
第7行通过subscriber对应的eventType从typesBySubscriber中remove()移除。
for循环中遍历subscribedTypes,调用unsubscribeByEventType方法。下面看看unsubscribeByEventType()方法做了什么
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--;
}
}
}
}
上面代码第2行通过eventTyoe来得到对应的Subscriptions(订阅对象集合),并在for循环中if判断如果Subscription(订阅对象)的subscriber(订阅者)属性 == 传进来的subscriber,则从Subscriptions中移除该Subscription。
我们简单串联一下所使用的方法:
构造方法:
getDefault()——EventBus()
查找订阅者的订阅方法:
register()——findSubscriberMethods()——findUsingInfo()——findUsingReflectionInSingleClass()
订阅者注册:
register()——subscribe()
事件发送:
post()——postingSingleEvent()——postSingleEventForEventType()——postToSubscription()
取消注册:
unregister()——unsubscribeByEventType()
本文摘抄自《Android进阶之光——刘望舒》,为自己学习路程中的记录,不以盈利为目的。
欢迎指正。