虽然EventBus现在有点过时了,但是其蕴含的思想还是很值得我们去学习的。
个人认为EventBus的魅力在于避免了回调带来的接口爆炸,今天来看一下EventBus的粘性事件的原理。
1. 粘性事件的用法:
- 订阅的时候
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public fun onEvent() {
}
很简单,就是在订阅的时候加上sticky = true
- 发布的时候
EventBus.getDefault().postSticky(this)
只是将一般的post改为postSticky
2. 事件的接收
- 一般事件的接收,当我们调用EventBus.getDefault().register(this)的时候,会通过通过注解去拿我们注册的方法,代码如下:
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
将方法拿出来之后就会和具体的事件类型绑定:
subscriptionsByEventType.put(eventType, subscriptions);
当我们调用post的时候,会去刚才的缓存里查询:
subscriptions = subscriptionsByEventType.get(eventClass);
然后根据反射调用我们注册的方法。
所谓粘性事件就是在事件发送时,接收者还不存在,当接收方注册的时候再处理该事件。
- 粘性事件的接收,在我们调用postSticky,会把粘性事件先保存下来:
stickyEvents.put(event.getClass(), event);
当EventBus遍历订阅方法时根据注解判断当前方法是否是sticky,如果是的:
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<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, 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);
}
}
就拿到这个粘性事件,直接调用该订阅方法:
postToSubscription(subscription, event, postingState.isMainThread);