EventBus原始碼解讀詳細註釋(5)事件訊息繼承性分析 eventInheritance含義
[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)
如果post(A),A extends B implements C,D implements C
那麼onEvent(A)、onEvent(B)、onEvent(C)、onEvent(D)四個事件處理方法那些能得到呼叫呢
答案是onEvent(A)、onEvent(B)、onEvent(C)這三個
先用簡單的實驗驗證,然後原始碼分析
寫一個簡單的Activity測試
public class MainActivity extends Activity { private static final String TAG="EventBus"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onStart() { super.onStart(); Log.v(TAG, "onStart()"); EventBus.getDefault().register(this); EventBus.getDefault().post(new A()); } @Override protected void onStop() { super.onStop(); EventBus.getDefault().unregister(this); Log.v(TAG, "onStop()"); } public void onEvent(A msg){ Log.v(TAG, "onEvent(A msg)"); } public void onEvent(B msg){ Log.v(TAG,"onEvent(B msg)"); } public void onEvent(C msg){ Log.v(TAG,"onEvent(C msg)"); } public void onEvent(D msg){ Log.v(TAG,"onEvent(D msg)"); } }其中 A、B、C、D的繼承關係如下:
public class A extends B implements C{}
public class B {}
public interface C {}
public class D implements C{}讓程式跑起來,看一下log怎麼說:
V/EventBus: onStart()
V/EventBus: onEvent(A msg)
V/EventBus: onEvent(C msg)
V/EventBus: onEvent(B msg)
V/EventBus: onStop()
由此可知EventBus中:
如果post(A),A extends B implements C,D implements C
那麼onEvent(A)、onEvent(B)、onEvent(C)會被呼叫,onEvent(D)不會被呼叫
接下來看看原始碼怎麼實現:
/*在此標誌位為true的前提下 如果post(A),A extends B implements C,D implements C 那麼onEvent(A)、onEvent(B)、onEvent(C)會被呼叫,onEvent(D)不會被呼叫*/ private final boolean eventInheritance;這是一個成員屬性標誌位
釋出事件的時候呼叫的是post,post內部呼叫下邊這個方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
/*獲取事件的Class,所有事件的Class對應的訂閱者列表在register的時候是已經儲存了的*/
Class<?> eventClass = event.getClass();
/*根據事件的Class找到訂閱者的標誌狀態,初始化為false*/
boolean subscriptionFound = false;
/*
* 比如 A extends B implements C 釋出者post(A),那麼找訂閱者的時候不僅要找訂閱了事件A的訂閱者
* 還要找訂閱了B和C的訂閱者*/
if (eventInheritance) {
/*找到事件的所有父類和所有實現的介面*/
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
/*不考慮事件的繼承性的話,那麼處理起來就比較簡單了*/
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
前邊說過了EventBus維護了兩個重要的map。其中一個就是事件的Class到能處理此事件的所有訂閱者列表的map,因此不僅要把事件的Class存入map中的訂閱者列表,還要把事件的所有父類和所有實現的介面的Class存入訂閱者列表。下邊是找到某個類所有父類和所有實現介面的方法:
/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
/*找到事件的所有父類和實現的介面,以Class列表的形式返回*/
private List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
/*private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<Class<?>, List<Class<?>>>();*/
synchronized (eventTypesCache) {
/*檢視快取,看能否命中*/
List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
/*快取不命中*/
if (eventTypes == null) {
/*建立事件型別列表*/
eventTypes = new ArrayList<Class<?>>();
Class<?> clazz = eventClass;
/*getSuperclass()返回null的情況:Class表示的類為Object、基本資料型別、介面或者void*/
while (clazz != null) {
eventTypes.add(clazz);
/*把介面對應的Class也新增進Class列表
* clazz.getInterfaces():返回clazz表示的類直接實現的介面的Class列表,不包括間接實現的介面
* */
addInterfaces(eventTypes, clazz.getInterfaces());
/** public Class<? super T> getSuperclass() :
* Returns the Class object which represents the superclass of the
* class represented by this Class. If this Class represents
* the Object class, a primitive type, an interface or void then the
* method returns null. If this Class represents an array
* class then the Object class is returned.
*/
clazz = clazz.getSuperclass();
}
/*找到一個事件的所有父類和所有實現介面的Class挺複雜的,迴圈加遞迴的,還是加入快取機制提高效能吧*/
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
/** Recurses through super interfaces. 獲取某個類直接實現的所有介面,包括間接實現的
* @param eventTypes
* @param interfaces*/
static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
/*對這個類直接實現的每個介面開始遍歷*/
for (Class<?> interfaceClass : interfaces) {
/*如果這個介面還沒有新增到列表接把他新增到列表*/
if (!eventTypes.contains(interfaceClass)) {
eventTypes.add(interfaceClass);
/*把這個介面所直接實現的所有介面的Class也新增進列表 遞迴呼叫*/
addInterfaces(eventTypes, interfaceClass.getInterfaces());
}
}
}
相關文章
- EventBus詳解及原始碼分析原始碼
- 生命週期詳細解讀(含部分原始碼)原始碼
- EventBus 3.0+ 原始碼詳解(史上最詳細圖文講解)原始碼
- Bootstrap的Model原始碼詳細註釋 (轉)boot原始碼
- 【UGUI原始碼分析】Unity遮罩之Mask詳細解讀UGUI原始碼Unity遮罩
- EventBus原始碼分析原始碼
- SpringMVC原始碼剖析5:訊息轉換器HttpMessageConverter與@ResponseBody註解SpringMVC原始碼HTTP
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- EventBus 原始碼分析(上篇)原始碼
- EventBus 3.0 原始碼分析原始碼
- 「Android」分析EventBus原始碼擴充套件Weex事件機制Android原始碼套件事件
- Android Handler訊息機制原始碼解讀Android原始碼
- 【UGUI原始碼分析】Unity遮罩之RectMask2D詳細解讀UGUI原始碼Unity遮罩
- Vue 原始碼解讀(5)—— 全域性 APIVue原始碼API
- Abp領域事件(EventBus)原始碼解析事件原始碼
- 訊息推送介面設計(內含原始碼)原始碼
- 【原始碼解讀】js原生訊息提示外掛原始碼JS
- JavaScript繼承詳解(二)JavaScript繼承
- 三方庫原始碼筆記(1)-EventBus 原始碼詳解原始碼筆記
- Vue事件匯流排(EventBus)使用詳細介紹Vue事件
- Spring的IOC常用註解(含原始碼)Spring原始碼
- 超詳細的 Bert 文字分類原始碼解讀 | 附原始碼文字分類原始碼
- 史上最為詳細的javascript繼承JavaScript繼承
- ES6中的類繼承和ES5中的繼承模式詳解繼承模式
- Android 原始碼分析之 EventBus 的原始碼解析Android原始碼
- 「MoreThanJava」Day 5:物件導向進階——繼承詳解Java物件繼承
- Giraph原始碼分析(三)—— 訊息通訊原始碼
- Spring Ioc原始碼分析系列--Ioc容器註冊BeanPostProcessor後置處理器以及事件訊息處理Spring原始碼Bean事件
- Tarjan演算法及其應用 總結+詳細講解+詳細程式碼註釋演算法
- java繼承基礎詳解Java繼承
- js 組合繼承詳解JS繼承
- vue的事件冒泡 最詳細解釋版本Vue事件
- 史上最詳細ConvLstm的pytorch程式碼解讀分析PyTorch
- dotnet 讀 WPF 原始碼筆記 從 WM_POINTER 訊息到 Touch 事件原始碼筆記事件
- 一文讀懂Guava EventBus(訂閱\釋出事件)Guava事件
- java封裝繼承以及多型(含程式碼)Java封裝繼承多型
- JAVA中的註解可以繼承嗎?Java繼承
- 深入 JavaScript 原型繼承原理——babel 編譯碼解讀JavaScript原型繼承Babel編譯
- Rank & Sort Loss for Object Detection and Instance Segmentation 論文解讀(含核心原始碼詳解)ObjectSegmentation原始碼