EventBus原始碼解讀詳細註釋(4)register時重新整理的兩個map
[EventBus原始碼分析(一):入口函式提綱挈領(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51802172)
[EventBus原始碼分析(二):register方法儲存事件的訂閱者列表(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51819508)
[EventBus原始碼分析(三):post方法釋出事件【獲取事件的所有訂閱者,反射呼叫訂閱者事件處理方法】(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51821143)
[EventBus原始碼分析(四):執行緒模型分析(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51832001)
[EventBus原始碼解讀詳細註釋(1)register的幕後黑手](http://blog.csdn.net/wangshihui512/article/details/50914817)
[EventBus原始碼解讀詳細註釋(2)MainThread執行緒模型分析](http://blog.csdn.net/wangshihui512/article/details/50934012)
[EventBus原始碼解讀詳細註釋(3)PostThread、MainThread、BackgroundThread、Async四種執行緒模式的區別](http://blog.csdn.net/wangshihui512/article/details/50935729)
[EventBus原始碼解讀詳細註釋(4)register時重新整理的兩個map](http://blog.csdn.net/wangshihui512/article/details/50938663)
[EventBus原始碼解讀詳細註釋(5)事件訊息繼承性分析 eventInheritance含義](http://blog.csdn.net/wangshihui512/article/details/50947102)
[EventBus原始碼解讀詳細註釋(6)從事件釋出到事件處理,究竟發生了什麼!](http://blog.csdn.net/wangshihui512/article/details/50949960)
EventBus中有兩個重要的map,一個是事件到訂閱者列表的map,另一個是訂閱者到事件列表的map,每次register的時候都要動態重新整理這兩個map的資料。正是因為有了這兩個map,EventBus在post事件的時候才可以根據事件型別找到所有訂閱了此事件的訂閱者,然後使用反射呼叫訂閱者的事件處理方法。
先看看EventBus中這兩個map是如何定義的
/*事件到訂閱者列表的map,key是事件,也就是訊息處理方法的引數的Class,value是所有的訂閱此事件的訂閱者列表*/ private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType; /*訂閱者到訂閱者訂閱的所有事件列表的map,key是訂閱者,value是該訂閱者訂閱的所有事件的列表*/ private final Map<Object, List<Class<?>>> typesBySubscriber;在register的時候會動態的重新整理這兩個map,主要是重新整理map的value即重新整理列表。
private synchronized void register(Object subscriber, boolean sticky, int priority) {
/*getClass():* Returns the unique instance of Class that represents this object's class.*/
/*過濾出訂閱者的所有事件處理方法(包括父類的),以列表形式返回*/
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
for (SubscriberMethod subscriberMethod : subscriberMethods) {
/*遍歷,對訂閱者的每一個事件處理方法進行訂閱*/
subscribe(subscriber, subscriberMethod, sticky, priority);
}
}
subscribe方法中主要做了一件事,就是更新那兩個重要的map
/**
* @param subscriber 訂閱者
* @param subscriberMethod 訂閱者的事件處理方法
* @param sticky 是否是粘性事件
* @param priority 優先順序
*/
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
/*每次subscribe都要更新兩個map,事件到訂閱者列表的map,和訂閱者到事件列表的map*/
/*下邊的程式碼先更新事件到訂閱者列表的map,主要是更新此事件的訂閱者列表*/
/*獲取訊息型別,也就是事件處理方法的引數型別*/
Class<?> eventType = subscriberMethod.eventType;
/*private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
* subscriptionsByEventType: key:訊息型別(事件處理方法引數型別),value:接受此訊息型別的所有訂閱者列表
* */
/*獲取所有接受此訊息型別的訂閱者列表,然後把新的訂閱者加入此列表*/
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
/*根據訂閱者,事件、優先順序封裝一個新的訂閱者封裝類Subscription*/
Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
/*如果此訊息型別的訂閱者列表為null,表示還沒有訂閱者訂閱此型別訊息,就建立一個訂閱者列表*/
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<Subscription>();
/*將事件和事件對應的訂閱者列表加入全域性的map*/
subscriptionsByEventType.put(eventType, subscriptions);
} else {
/*如果接收此訊息型別的訂閱者列表不為空,並且列表裡邊已經有此訂閱者,丟擲重複註冊異常*/
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
// subscriberMethod.method.setAccessible(true);
/*更新事件的訂閱者列表*/
/*將新的註冊的訂閱者根據優先順序插入到合適位置,priority表示優先順序,按照該數值從大到小排列*/
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
/*按照優先順序遍歷 逐個比較*/
if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
/*注意寫時複製的思想,CopyOnWriteArrayList增加資料的原始碼如下所示*/
/*
public synchronized void add(int index, E e) {
Object[] newElements = new Object[elements.length + 1];
public static native void arraycopy(Object src, int srcPos,Object dst, int dstPos, int length);
* Copies length elements from the array src,
* starting at offset srcPos, into the array dst,
* starting at offset dstPos.
* @param src the source array to copy the content.
* @param srcPos the starting index of the content in {@code src}.
* @param dst the destination array to copy the data into.
* @param dstPos the starting index for the copied content in {@code dst}.
* @param length the number of elements to be copied.
System.arraycopy(elements, 0, newElements, 0, index);
newElements[index] = e;
System.arraycopy(elements, index, newElements, index + 1, elements.length - index);
elements = newElements;
}
*/
/*CopyOnWriteArrayList並不是按照資料結構裡邊將的那樣通過資料移位來新增元素,那樣效率太低了
* 而是先建立一個比原來列表size大1的新列表,將新新增資料前邊的所有資料整體賦值到新列表前邊,
* 將要新增的新數新增在新列表的後邊,然後把剩下的一起復制到新列表*/
subscriptions.add(i, newSubscription);
break;
}
}
/*然後接下來更新訂閱者到事件列表的map,主要是更新事件列表*/
/*private final Map<Object, List<Class<?>>> typesBySubscriber;
* typesBySubscriber :key訂閱者 value訂閱者訂閱的訊息列表
* typesBySubscriber是EventBus的成員屬性,表示一個map,key是訂閱者,value是該訂閱者訂閱的所有事件的列表,
* 是全域性的,要囊括所有訂閱者
* subscriptionsByEventType也是EventBus的成員屬性,表示一個map,key是事件,value是訂閱了改事件的所有訂閱者的列表,
* 是全域性的,要囊括所有事件*/
/*獲取訂閱者的接受的所有訊息型別列表*/
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
/*如果此訂閱者還沒有以前沒有訂閱事件,則建立列表,新增事件*/
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<Class<?>>();
/*typesBySubscriber是EventBus的類成員*/
typesBySubscriber.put(subscriber, subscribedEvents);
}
/*將此事件新增到訂閱者訂閱的事件的列表,更新事件列表*/
subscribedEvents.add(eventType);
/*處理粘性事件*/
if (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);
}
}
}
相關文章
- EventBus原始碼解讀詳細註釋(1)register的幕後黑手原始碼
- EventBus原始碼解讀詳細註釋(2)MainThread執行緒模型分析原始碼AIthread執行緒模型
- EventBus原始碼解讀詳細註釋(5)事件訊息繼承性分析 eventInheritance含義原始碼事件繼承
- EventBus原始碼解讀詳細註釋(6)從事件釋出到事件處理,究竟發生了什麼!原始碼事件
- EventBus原始碼解讀詳細註釋(3)PostThread、MainThread、BackgroundThread、Async四種執行緒模式的區別原始碼threadAI執行緒模式
- Bootstrap的Model原始碼詳細註釋 (轉)boot原始碼
- EventBus 3.0+ 原始碼詳解(史上最詳細圖文講解)原始碼
- EventBus詳解及原始碼分析原始碼
- 超詳細的 Bert 文字分類原始碼解讀 | 附原始碼文字分類原始碼
- 詳細解讀微服務的兩種模式微服務模式
- 生命週期詳細解讀(含部分原始碼)原始碼
- 老馬的春天:SDWebImage原始碼詳細解讀系列Web原始碼
- 安卓第一個作品 檔案管理器 附原始碼帶詳細註釋安卓原始碼
- 三方庫原始碼筆記(1)-EventBus 原始碼詳解原始碼筆記
- PostgreSQL FSM(Free Space Map) 原始碼解讀SQL原始碼
- 【UGUI原始碼分析】Unity遮罩之Mask詳細解讀UGUI原始碼Unity遮罩
- sqlHelper類的中文 詳細註釋SQL
- Promises A+規範原文解讀 + es6實現(附詳細註釋)Promise
- PostgreSQL 原始碼解讀(19)- 查詢語句#4(ParseTree詳解)SQL原始碼
- antd原始碼解讀(4)- ButtonGroup原始碼
- RxJava2原始碼解讀之 Map、FlatMapRxJava原始碼
- EventBus原始碼分析(二):register方法儲存事件的訂閱者列表(2.4版本)原始碼事件
- 【原始碼解讀】asp.net core原始碼啟動流程精細解讀原始碼ASP.NET
- 詳解Java 容器(第④篇)——容器原始碼分析 - MapJava原始碼
- Leetcode:2. 兩數相加(C++帶詳細註釋)LeetCodeC++
- register_globals 詳解
- 【UGUI原始碼分析】Unity遮罩之RectMask2D詳細解讀UGUI原始碼Unity遮罩
- TERMIOS_H 詳細註釋iOS
- Kafka原始碼篇 --- 可能是你看過最詳細的RecordAccumulator解讀Kafka原始碼
- EventBus原始碼分析原始碼
- EventBus原始碼解析原始碼
- JavaScript註釋:單行註釋和多行註釋詳解JavaScript
- Spring 註解學習 詳細程式碼示例Spring
- Python實現快遞分揀小程式(附原始碼和超詳細註釋)Python原始碼
- Java註解最全詳解(超級詳細)Java
- 5.4 以太坊原始碼詳解4原始碼
- tar命令的詳細解釋
- redux v3.7.2原始碼詳細解讀與學習之composeRedux原始碼