好多分析EventBus的文章,喜歡上來就貼源碼,我看了好屢次老是迷迷糊糊的,此次花時間完全整理一下EventBus,發現EventBus核心其實就是三幅圖,這三幅圖涉及的是三個HashMap表,弄懂這三幅圖那麼EventBus就懂了。java
先看一段在activity中註冊和反註冊EventBus的代碼。ide
onStart{
EventBus.getDefault().register(this);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent1(Event1 event) {
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent2(Event2 event) {
}
onStop{
EventBus.getDefault().register(this);
}
複製代碼
看上面的代碼,註冊監聽的是activity,稱爲subscriber,在activity中監聽了Event1和Event2兩個事件,如今在另外一個位置執行了一段代碼:post
EventBus.getDefault().post(new Event1());
複製代碼
這個時候,activity中的onEvent1就會收到事件。下面引入第一幅圖: 性能
如圖所示,一個Subscribe對應多個Event,Subsribe就是上面經過register方法註冊的對象,好比activity。這幅圖對應EventBus中一個Map結構:private final Map<Object, List<Class<?>>> typesBySubscriber;
複製代碼
EventBus會在對象register時,使用反射機制,遍歷對象的方法,將帶有@Subscribe標籤而且合法的方法加入到typesBySubscriber。typesBySubscriber是HashMap形式,key是註冊的對象自己,因爲一個註冊的對象中可能有多個監聽事件,因此value是用list保存的Event。this
看下register方法中如何處理的spa
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
}
複製代碼
上面的代碼主要作兩件事:一、經過反射遍歷註冊對象的方法,獲取其中帶有@Subscribe標籤的方法而且放在一個列表中,最後以註冊對象爲key,@Subscribe的方法列表做爲value放在HashMap中,就是上圖的形式。code
思考cdn
一、爲何要將註冊監聽對象做爲key,監聽事件列表做爲value放在HashMap中? 要弄懂一個問題,EventBus是觀察者模式,上面的activity也就是subscribe是訂閱者,activity中的event是訂閱事件,一個訂閱者能夠訂閱多個事件,移除一個訂閱者的監聽事件時,應該將其中全部的event的事件移除。 也就是說在反註冊的時候,會經過Subsribe來查找到其中全部額event進行反註冊。對象
EventBus.getDefault().post(new Event1());
複製代碼
的時候全部註冊監聽了Event1的監聽都會要會收到回調,看下subsciption的結構blog
subsciption中包含,訂閱的事件和訂閱者自己,上面中全部的event就是訂閱的事件,在Android中訂閱的事件代碼以下:@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(Event event) {
}
複製代碼
而subsriber就是訂閱者好比會在activity的onstart中執行
....
EventBus.getDefault().register(this);
複製代碼
那麼subsribe就是activity。
思考 爲何須要保存Event和subsribe對應的關係表?
這是由於一個Event可能會有被多個subsribe訂閱,因此有當執行post(Event)的時候會查找到全部訂閱了Event事件的subscribe並調用其中的event方法。下面看下post方法:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> 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;
}
}
複製代碼
post和postSticky主要都會調用到上面的方法,上面方法中subscriptionsByEventType.get(eventClass)
就是經過event的類型找上面的表中找到對應的subscriptions進行通知的。
在看第三幅圖以前思考一個問題,postSticky究竟是怎麼執行的?爲何先執行postSticky,後執行register仍是能夠監聽到event事件? 先看postSticky代碼:
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
複製代碼
原來執行postSticky的時候會將event.getclass和event保存起來,而後再看下subscribe代碼:
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);
複製代碼
先判斷註冊監聽的event是否是sticky的若是是就會用stickEvents表中找到stickyEvent若是若是註冊的事件event和stickyEvent同樣那麼就會執行一次postToSubscription方法,也就是調用註冊的方法執行。
一、要理解EventBus就要從register,unRegister,post,postSticky方法入手。要理解register實質上是將訂閱對象(好比activity)中的每一個帶有subscriber的方法找出來,最後得到調用的就是這些方法。訂閱對象(好比activity)是一組event方法的持有者。
二、後註冊的對象中sticky方法可以收到以前的stickyEvent方法的緣由是EventBus中維護了stickyEvent的hashMap表,在subsribe註冊的時候就遍歷其中有沒有註冊監聽stickyEvent若是有就會執行一次回調。
一、使用的時候有定義不少event類, 二、event在註冊的時候會調用反射去遍歷註冊對象的方法在其中找出帶有@subscriber標籤的方法,性能不高。 三、須要本身註冊和反註冊,若是忘了反註冊就會致使內存泄漏