前言
粘性事件是指:發(fā)布者發(fā)送事件的動作發(fā)生在訂閱者訂閱該事件的動作之前,訂閱者在訂閱之后,仍然可以處理該事件。
我們在發(fā)送粘性事件時,通常是這樣寫的:
EventBus.getDefault().postSticky(event);
往下看看postSticky的邏輯。
一、主要流程
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
post(event);
}
postSticky的邏輯簡單明了,首先將事件存入stickyEvents里,然后調用普通事件的post方法,執(zhí)行與普通post相同的邏輯。
讀者看到這里,不知道會不會有疑問:
- 粘性事件的發(fā)布和普通事件的發(fā)布好像沒什么區(qū)別,它是怎么做到粘性的效果呢?
- 在register的時候,有調用了checkPostStickyEventToSubscription方法,該方法和postSticky里的post方法最終都調用了postToSubscription,這樣不就重復了嗎?
讀者請仔細觀察,在postSticky方法里,是有把事件緩存到stickyEvents中的。postSticky里的post方法,是訂閱者的訂閱事件的動作發(fā)生在粘性事件發(fā)布之前,此時粘性事件相當于普通事件,所以直接調用post處理即可。但如果訂閱者的訂閱事件的動作發(fā)生在粘性事件發(fā)布之后呢?此時就輪到stickyEvents起作用了,在注冊方法里,會取出所有未處理的緩存的粘性事件,發(fā)送到checkPostStickyEventToSubscription處理,這樣不就達到粘性事件的處理效果了嗎?
其實這種場景在實際開發(fā)中是很常見的。比如我們在某個非UI線程發(fā)布一個事件,在訂閱該事件的訂閱方法里去啟動某個Activity,此時,由于事件發(fā)布和Activity啟動不在同一個線程,且Activity啟動的速度和事件發(fā)布的速度也不可知,就有可能出現(xiàn)兩種情況(發(fā)布普通事件的場景):
- Activity先起來,事件后發(fā)送,此時沒有添加sticky=true的訂閱方法可以處理到該事件
- Activity后起來,事件先發(fā)送,此時沒有添加sticky=true的訂閱方法就處理不到該事件了
而粘性事件正好可以處理場景2的需求。
結束語
那么,有聰明的讀者就會說了:那直接把應用中的所有事件都以粘性事件發(fā)布,這樣不就可以高枕無憂了?
其實不然。首先,粘性事件是以Map緩存的,事件越多,越占內存;其次,每次注冊執(zhí)行register時,都會將所有緩存的粘性事件調用訂閱方法處理,如果處理過的粘性事件沒有清除,對于應用功能可能是有影響的。建議讀者不要圖省事而種下禍根。