EventBus原始碼解讀詳細註釋(1)register的幕後黑手
[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)
register(this)就是去當前類,遍歷所有的方法,按照事件處理方法的命名規則約束(onEvent開頭,只有一個引數,非static,非abstract的public方法)過濾出事件處理方法然後進行儲存。然後迴圈遍歷當前類的父類,做同樣的處理。
通過閱讀原始碼發現如果子類沒有覆寫父類的事件處理方法,那麼父類的事件處理方法將會加入事件處理方法列表。
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);
}
}
/**
* @param subscriberClass
* @return
*/
/*訂閱者 subscriberClass:註冊EventBus的Activity或其他元件,EventBus.getDefault().register(this)中的this*/
/*方法findSubscriberMethods的作用是過濾出訂閱者的所有事件處理方法方法,以列表形式返回*/
/*在EventBus中的觀察者通常有四種訂閱函式(就是某件事情發生被呼叫的方法)
1、onEvent
2、onEventMainThread
3、onEventBackground
4、onEventAsync
這四種訂閱函式都是使用onEvent開頭的,它們的功能稍有不同,在介紹不同之前先介紹兩個概念:
告知觀察者事件發生時通過EventBus.post函式實現,這個過程叫做事件的釋出,觀察者被告知事件發生叫做事件的接收,是通過下面的訂閱函式實現的。
onEvent:如果使用onEvent作為訂閱函式,那麼該事件在哪個執行緒釋出出來的,onEvent就會在哪個執行緒中執行,也就是說釋出事件和接收事件執行緒在同一個執行緒。
使用這個方法時,在onEvent方法中不能執行耗時操作,如果執行耗時操作容易導致事件分發延遲。
onEventMainThread:如果使用onEventMainThread作為訂閱函式,那麼不論事件是在哪個執行緒中釋出出來的,都會在主執行緒中呼叫事件處理方法,這個在Android中是非常有用的,因為在Android中只能在UI執行緒中更新UI,所以在onEvnetMainThread方法中是不能執行耗時操作的。
onEvnetBackground:如果使用onEventBackgrond作為訂閱函式,那麼如果事件是在UI執行緒中釋出出來的,那麼onEventBackground就會在子執行緒中執行,如果事件本來就是子執行緒中釋出出來的,那麼onEventBackground函式直接在該子執行緒中執行。
onEventAsync:使用這個函式作為訂閱函式,那麼無論事件在哪個執行緒釋出,都會建立新的子執行緒在執行onEventAsync.*/
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
/*getName():Returns the name of the class represented by this Class 返回訂閱者的類名,比如xxx.xxx.xxx.MainActivity*/
String key = subscriberClass.getName();
List<SubscriberMethod> subscriberMethods;
/* private static final Map<String, List<SubscriberMethod>> methodCache = new HashMap<String, List<SubscriberMethod>>();*/
/*方法快取就是一個靜態最終的HashMap,key是訂閱者的類名,value是訂閱者事件處理方法的列表*/
/*先讀快取,看能否命中*/
synchronized (methodCache) {
subscriberMethods = methodCache.get(key);
}
/*如果快取命中,直接返回快取中的事件處理方法列表*/
if (subscriberMethods != null) {
return subscriberMethods;
}
/*快取不命中,開始按照事件處理方法的命名規則進行過濾*/
subscriberMethods = new ArrayList<SubscriberMethod>();
Class<?> clazz = subscriberClass;
/*eventTypesFound存放的是事件處理方法的過濾結果,key就是過濾出來的事件處理方法,value就是宣告瞭這個事件處理方法的訂閱者的Class*/
/*因為是迴圈處理訂閱者的所有父類的,所以如果子類覆寫了父類的事件處理方法,那麼父類和子類的事件處理方法名稱和引數完全一致
* 而事件處理方法名稱和引數是作為eventTypeFound的key儲存的,key必須唯一*/
HashMap<String, Class> eventTypesFound = new HashMap<String, Class>();
/*注意這個StringBuilder類是在迴圈外建立的,在迴圈內建立就太沖動了*/
StringBuilder methodKeyBuilder = new StringBuilder();
/*迴圈的最後一句話:clazz = clazz.getSuperclass(); 表示不僅要找當前類的事件處理方法,還要找所有父類的事件處理方法*/
while (clazz != null) {
String name = clazz.getName();
/*如果類名是以java. javax. android. 為字首,說明是系統類,不處理系統的類,直接結束迴圈,這是出於效能的考慮*/
if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
// Skip system classes, this just degrades performance
break;
}
// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)
/*從EventBus2.2版本開始要求事件處理方法必須是公開的方法*/
try {
// This is faster than getMethods, especially when subscribers a fat classes like Activities
/*
getDeclaredMethods():返回所有方法,不僅僅是公開的,但不包括繼承的方法
getMethods():返回所有公開方法,包括繼承來的方法,如果訂閱者是個比較複雜的類,那麼getDeclaredMethods()速度要快於getMethods()
getDeclaredMethods():Returns an array containing Method objects
for all methods declared in the class represented by this Class. */
Method[] methods = clazz.getDeclaredMethods();
/*對訂閱者的所有方法進行過濾,得到事件處理方法列表*/
filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods);
} catch (Throwable th) {
th.printStackTrace();
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
Method[] methods = subscriberClass.getMethods();
subscriberMethods.clear();
eventTypesFound.clear();
filterSubscriberMethods(subscriberMethods, eventTypesFound, methodKeyBuilder, methods);
break;
}
/*獲取父類,對訂閱者的父類進行同樣的處理*/
clazz = clazz.getSuperclass();
}
/*如果元件註冊了EventBus,就成為了訂閱者,訂閱者不能沒有事件處理方法,否則丟擲異常*/
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "
+ ON_EVENT_METHOD_NAME);
} else {
/*過濾一次事件處理方法還是挺麻煩的,所以還是加入快取吧*/
synchronized (methodCache) {
methodCache.put(key, subscriberMethods);
}
return subscriberMethods;
}
}
/**對訂閱者的所有方法進行過濾,得到事件處理方法列表
* @param subscriberMethods 返回的事件處理方法列表
* @param eventTypesFound 過濾出的時間處理方法
* @param methodKeyBuilder
* @param methods 所有方法
*/
private void filterSubscriberMethods(List<SubscriberMethod> subscriberMethods,
HashMap<String, Class> eventTypesFound, StringBuilder methodKeyBuilder,
Method[] methods) {
/*遍歷每個方法,對每個方法進行處理,判斷是否為事件處理方法*/
for (Method method : methods) {
/*得到方法名*/
String methodName = method.getName();
/*private static final String ON_EVENT_METHOD_NAME = "onEvent";*/
/*如果方法名以onEvent開頭就接著處理*/
if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {
/*獲取該方法的修飾符*/
int modifiers = method.getModifiers();
/*獲取宣告瞭這個方法的類*/
/*getDeclaringClass():returns the class that declares this method.*/
Class<?> methodClass = method.getDeclaringClass();
/* private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;*/
/*如果是非abstract、static的public方法,接著處理*/
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
/*獲取該方法的引數型別列表*/
Class<?>[] parameterTypes = method.getParameterTypes();
/*事件處理方法約定只有一個引數*/
if (parameterTypes.length == 1) {
/*根據方法名判斷執行緒型別*/
ThreadMode threadMode = getThreadMode(methodClass, method, methodName);
/*如果這個方法不是事件處理方法,跳出這次迴圈*/
if (threadMode == null) {
continue;
}
/*獲取引數型別,事件處理函式只有一個引數,所以取引數列表的第一項*/
Class<?> eventType = parameterTypes[0];
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(methodName);
methodKeyBuilder.append('>').append(eventType.getName());
/*舉個例子,如果事件處理函式為 onEvent(AutoRefreshMsg msg)
* 那麼methodKey就為onEvent>AutoRefreshMsg*/
String methodKey = methodKeyBuilder.toString();
/*HashMap<String, Class> eventTypesFound 是傳入的引數*/
/*eventTypesFound 中key為onEvent>AutoRefreshMsg這種格式的字串,value為宣告瞭該事件處理方法的類*/
/* HashMap : public V put(K key, V value)
* Maps the specified key to the specified value.
* @param key the key.
* @param value the value.
* @return the value of any previous mapping with the specified key or
* code null if there was no such mapping.
* 如果HashMap之前沒有這樣的K V對,或者說是這樣的K V對第一次新增到HashMap,就返回null
*/
/* methodClassOld表示之前是否已經儲存過了定義了這個事件處理方法的類,如果沒有,那麼methodClassOld==null*/
/*注意HashMap的put方法的返回值,返回對應k之前儲存的value或者null如果HashMap*/
/*注意對訂閱者事件處理方法的過濾是先過濾當前訂閱者,然後迴圈過濾當前訂閱者的父類*/
/*所以如果子類覆寫了父類的事件處理方法,那麼肯定先處理子類
* 先把此事件處理方法和子類的類Class儲存在eventTypesFound
* 然後再下一次迴圈處理父類的時候,呼叫map的put方法,因為子類覆寫了父類的事件處理方法
* 所以key值存在,put方法返回之前對用的value,也就是子類的Class*/
Class methodClassOld = eventTypesFound.put(methodKey, methodClass);
/* public boolean isAssignableFrom(Class<?> c)
isAssignableFrom:Can c be assigned to this class */
/* Class<?> methodClass = method.getDeclaringClass();*/
/*注意這裡或運算的短路性質*/
/* instanceof 針對例項 isAssignableFrom針對class物件*/
/* new A() instanceof B 判斷A物件是否是B類的子類或B類的例項*/
/* B.class.isAssignableFrom(A.class) A類是否可以賦值給B類,也就是判斷B是不是A的父類*/
/*對已事件處理方法,子類和父類的都一樣,所以只把最底層的訂閱者的事件處理方法加入事件處理方法列表
* eventTypesFound需要儲存事件處理方法和Class類名,在子類、父類、父類的父類中,事件處理方法名只有把一個(覆寫)
* Class名多個,規定只儲存最繼承層次最底層那個子類的Class作為value*/
/*如果子類沒有覆寫父類的事件處理方法,那麼就把父類的事件處理方法加入事件處理方法列表*/
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
/*子類中沒找到才新增*/
/* List<SubscriberMethod> subscriberMethods 方法傳進來的引數*/
subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));
} else {
/*HashMap<String, Class> eventTypesFound 是傳入的引數*/
/*eventTypesFound 中key為onEvent>AutoRefreshMsg這種格式的字串,value為宣告瞭該事件處理方法的類*/
// Revert the put, old class is further down the class hierarchy
/*注意是先處理子類後處理父類*/
eventTypesFound.put(methodKey, methodClassOld);
}
}
} else if (!skipMethodVerificationForClasses.containsKey(methodClass)) {
Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + methodClass + "."
+ methodName);
}
}
}
}
/**
* 根據方法名稱判斷執行緒型別
* @param clazz 訂閱者
* @param method
* @param methodName 以onEvent開頭的非static、abstract的public方法
* @return
*/
private ThreadMode getThreadMode(Class<?> clazz, Method method, String methodName) {
/*private static final String ON_EVENT_METHOD_NAME = "onEvent";*/
/*去掉方法名前邊的不變數onEvent,留下後邊的變數區分執行緒型別*/
String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());
ThreadMode threadMode;
/*四種執行緒模型*/
if (modifierString.length() == 0) {
/*onEvent:回撥函式和發起事件的函式會在同一個執行緒中執行*/
threadMode = ThreadMode.PostThread;
} else if (modifierString.equals("MainThread")) {
/*onEventMainThread:回撥函式會在主執行緒中執行,這個在Android中非常有用,因為在Android中禁止在子執行緒中修改UI*/
threadMode = ThreadMode.MainThread;
} else if (modifierString.equals("BackgroundThread")) {
/*onEventBackgroundThread:如果在主執行緒釋出事件,那麼在子執行緒中處理該事件;
吐過在子執行緒釋出事件,那麼事件處理方法就在這個子執行緒執行。*/
threadMode = ThreadMode.BackgroundThread;
} else if (modifierString.equals("Async")) {
/*onEventBusAsync:不管在哪個執行緒釋出事件,都會另起一個執行緒去處理事件。*/
threadMode = ThreadMode.Async;
} else {
/*private final Map<Class<?>, Class<?>> skipMethodVerificationForClasses;*/
/*判斷是不是可以跳過訂閱者方法校驗,不跳過就派出異常,跳過就返回null*/
if (!skipMethodVerificationForClasses.containsKey(clazz)) {
throw new EventBusException("Illegal onEvent method, check for typos: " + method);
} else {
threadMode = null;
}
}
return threadMode;
}
相關文章
- EventBus原始碼解讀詳細註釋(4)register時重新整理的兩個map原始碼
- EventBus原始碼解讀詳細註釋(2)MainThread執行緒模型分析原始碼AIthread執行緒模型
- EventBus原始碼解讀詳細註釋(5)事件訊息繼承性分析 eventInheritance含義原始碼事件繼承
- EventBus原始碼解讀詳細註釋(6)從事件釋出到事件處理,究竟發生了什麼!原始碼事件
- EventBus原始碼解讀詳細註釋(3)PostThread、MainThread、BackgroundThread、Async四種執行緒模式的區別原始碼threadAI執行緒模式
- Bootstrap的Model原始碼詳細註釋 (轉)boot原始碼
- EventBus 3.0+ 原始碼詳解(史上最詳細圖文講解)原始碼
- 三方庫原始碼筆記(1)-EventBus 原始碼詳解原始碼筆記
- EventBus詳解及原始碼分析原始碼
- 超詳細的 Bert 文字分類原始碼解讀 | 附原始碼文字分類原始碼
- 生命週期詳細解讀(含部分原始碼)原始碼
- 老馬的春天:SDWebImage原始碼詳細解讀系列Web原始碼
- 【UGUI原始碼分析】Unity遮罩之Mask詳細解讀UGUI原始碼Unity遮罩
- 資料庫真爛的 幕後黑手 “們”資料庫
- sqlHelper類的中文 詳細註釋SQL
- preact原始碼解讀(1)React原始碼
- Promises A+規範原文解讀 + es6實現(附詳細註釋)Promise
- EventBus原始碼分析(二):register方法儲存事件的訂閱者列表(2.4版本)原始碼事件
- 【原始碼解讀】asp.net core原始碼啟動流程精細解讀原始碼ASP.NET
- register_globals 詳解
- Vue 原始碼解讀(1)—— 前言Vue原始碼
- 安卓第一個作品 檔案管理器 附原始碼帶詳細註釋安卓原始碼
- 【UGUI原始碼分析】Unity遮罩之RectMask2D詳細解讀UGUI原始碼Unity遮罩
- TERMIOS_H 詳細註釋iOS
- React Scheduler 原始碼詳解(1)React原始碼
- Kafka原始碼篇 --- 可能是你看過最詳細的RecordAccumulator解讀Kafka原始碼
- EventBus原始碼分析原始碼
- EventBus原始碼解析原始碼
- JavaScript註釋:單行註釋和多行註釋詳解JavaScript
- Python實現快遞分揀小程式(附原始碼和超詳細註釋)Python原始碼
- Spring 註解學習 詳細程式碼示例Spring
- 任天堂疑似開發工具、原始碼等機密資料洩露!16歲駭客為幕後黑手原始碼
- Java註解最全詳解(超級詳細)Java
- PostgreSQL 原始碼解讀(153)- 後臺程式#5(walsender#1)SQL原始碼
- PostgreSQL 原始碼解讀(124)- 後臺程式#4(autovacuum程式#1)SQL原始碼
- React-Redux 原始碼解讀(1)ReactRedux原始碼
- tar命令的詳細解釋
- redux v3.7.2原始碼詳細解讀與學習之composeRedux原始碼