前言
粘性事件是指:发布者发送事件的动作发生在订阅者订阅该事件的动作之前,订阅者在订阅之后,仍然可以处理该事件。
我们在发送粘性事件时,通常是这样写的:
EventBus.getDefault().postSticky(event);
往下看看postSticky的逻辑。
一、主要流程
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
post(event);
}
postSticky的逻辑简单明了,首先将事件存入stickyEvents里,然后调用普通事件的post方法,执行与普通post相同的逻辑。
读者看到这里,不知道会不会有疑问:
- 粘性事件的发布和普通事件的发布好像没什么区别,它是怎么做到粘性的效果呢?
- 在register的时候,有调用了checkPostStickyEventToSubscription方法,该方法和postSticky里的post方法最终都调用了postToSubscription,这样不就重复了吗?
读者请仔细观察,在postSticky方法里,是有把事件缓存到stickyEvents中的。postSticky里的post方法,是订阅者的订阅事件的动作发生在粘性事件发布之前,此时粘性事件相当于普通事件,所以直接调用post处理即可。但如果订阅者的订阅事件的动作发生在粘性事件发布之后呢?此时就轮到stickyEvents起作用了,在注册方法里,会取出所有未处理的缓存的粘性事件,发送到checkPostStickyEventToSubscription处理,这样不就达到粘性事件的处理效果了吗?
其实这种场景在实际开发中是很常见的。比如我们在某个非UI线程发布一个事件,在订阅该事件的订阅方法里去启动某个Activity,此时,由于事件发布和Activity启动不在同一个线程,且Activity启动的速度和事件发布的速度也不可知,就有可能出现两种情况(发布普通事件的场景):
- Activity先起来,事件后发送,此时没有添加sticky=true的订阅方法可以处理到该事件
- Activity后起来,事件先发送,此时没有添加sticky=true的订阅方法就处理不到该事件了
而粘性事件正好可以处理场景2的需求。
结束语
那么,有聪明的读者就会说了:那直接把应用中的所有事件都以粘性事件发布,这样不就可以高枕无忧了?
其实不然。首先,粘性事件是以Map缓存的,事件越多,越占内存;其次,每次注册执行register时,都会将所有缓存的粘性事件调用订阅方法处理,如果处理过的粘性事件没有清除,对于应用功能可能是有影响的。建议读者不要图省事而种下祸根。