1.EventBus源碼解析(一)—訂閱過程
2.EventBus源碼解析(二)—發(fā)布事件和注銷流程
3.EventBus源碼解析(三)—進階源碼
前言
最近發(fā)現(xiàn)EventBus用起來是真的方便凸克,本來對于EventBus我對于這個框架的源碼的閱讀的優(yōu)先級是比較低的议蟆,因為這個框架不像OkHttp,Glide那樣層層嵌套萎战,步步深入咐容,基本上有一定基礎(chǔ)的人對于EventBus的原理都會有一定的理解——反射。但是最近突然發(fā)現(xiàn)僅僅是了解這些是不夠的蚂维,如果細想一下會發(fā)現(xiàn)戳粒,EventBus的實現(xiàn)還是有許多值得學(xué)習(xí)的地方的,我來說一下讓我疑惑的問題以至于想讓我去追究EventBus底層源碼的問題吧鸟雏。
1.EventBus在接受事件的時候如何區(qū)分多個相同的Activity享郊?
2.EventBus事件的接收在父類和子類之間是什么規(guī)則?
3.EventBus對于多態(tài)類型的事件是如何識別的孝鹊?
4.EventBus只能用于Activity和Fragment之間嗎炊琉?
5.EventBus可以創(chuàng)建多個實例嗎?互相干擾嗎又活?
再沒有看EventBus源碼之前苔咪,上面這些問題,我是沒法回答的柳骄。意識到看源碼的必要性团赏,我提高的EventBus源碼閱讀的優(yōu)先級,本篇博客主要從分析注冊流程耐薯。
源碼分析
注冊流程
EventBus.getDefault().register(this);
EventBus的使用本篇博客就不講解了舔清,注冊的代碼很簡單,一行遍完成曲初,接下來詳細看看實現(xiàn)源碼体谒。
1.getDefault()
public static EventBus getDefault() {
//常規(guī)的雙重鎖單例模式,特殊的是構(gòu)造方法是公有的臼婆,也就是可以創(chuàng)建多個EventBus,互相不干擾
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
對于getDefault()不出意料果然是常規(guī)的雙重鎖的單例模式抒痒,但是這里有一個地方和平常的單例模式不同,平常的單例模式構(gòu)造方法往往是私有的颁褂,用于保證全局唯一故响,但是這里我們看一下EventBus的構(gòu)造函數(shù)傀广。
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
這里會發(fā)現(xiàn)EventBus的構(gòu)造方法是公有的,也就是說我們自己可以自己new一個EventBus的實例彩届,當(dāng)然EventBus也提供了EventBusBuilder供我們構(gòu)造使用伪冰。這里特意把構(gòu)造方法的注釋放了上來,大概翻譯一下吧惨缆。
創(chuàng)建一個EventBus實例糜值,每一個實例的事件傳遞都在自己的實例范圍,如果想統(tǒng)一管理坯墨,可以使用getDefault()方法寂汇。
這里通過注釋我們就可以解釋第五個問題了,當(dāng)然只是從注釋層面捣染,EventBus是可以創(chuàng)建多個實例的骄瓣,并且多個實例的發(fā)送的事件是互不干擾的
2.register(Object subscriber)
public void register(Object subscriber) {
//獲得訂閱者對應(yīng)的Class,MainActivity.class
Class<?> subscriberClass = subscriber.getClass();
//找到所有的訂閱的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
這里開始看注冊的過程,可以看到往往我們注冊時傳入的是this
,所以這里首先調(diào)用getClass(),獲得的就是MainActivity.class(舉例)耍攘,獲得完這個class對象后榕栏,會調(diào)用findSubscriberMethods
方法來找到該Class中所有的訂閱方法。
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//Cache中存在則直接從Cache中獲取
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
//運行是通過反射拿到
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//編譯期獲得
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//放入緩存
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
這里首先從緩存中獲取蕾各。METHOD_CACHE對應(yīng)的是在聲明的時候就初始化完成了,是一個ConcurrentHashMap
private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
可以看到這里的key是class對象扒磁,那么我們可以發(fā)現(xiàn),如果已經(jīng)通過反射得到的訂閱方法的類式曲,再次注冊的時候妨托,不會再次通過反射獲取。
下面可以看到對于ignoreGeneratedIndex
變量的判斷吝羞,這個變量默認是false兰伤,也就是默認的時候我們是通過編譯期注解來實現(xiàn)映射表的構(gòu)建的,本篇博客主要分析通過運行時反射來回去訂閱的方法的钧排,對于索引的方式敦腔,后面的博客如果有時間會考慮分析源碼。
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
//緩存中獲取恨溜,默認大小為4都數(shù)組符衔,沒有就new
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//findState保存注冊的訂閱者中的方法相關(guān)信息
findUsingReflectionInSingleClass(findState);
//向上繼續(xù)遍歷
findState.moveToSuperclass();
}
//返回方法集
return getMethodsAndRelease(findState);
}
這里可以看到首先獲取FindState對象,使用了prepareFindState
方法
private static final int POOL_SIZE = 4;
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
private FindState prepareFindState() {
//有點簡單粗暴的意思糟袁。柏腻。。
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
可以看到默認是有一個大小為4的數(shù)組用于緩存FindState對象的系吭,由于FindState對象比較大,所以EventBus考慮使用緩存進行復(fù)用颗品,當(dāng)然這個緩存實現(xiàn)起來也比較簡單粗暴~
接下來是一個循環(huán)肯尺。
while (findState.clazz != null) {
//findState保存注冊的訂閱者中的方法相關(guān)信息
findUsingReflectionInSingleClass(findState);
//向上繼續(xù)遍歷
findState.moveToSuperclass();
}
可以看到沃缘,此時我們的findState.clazz是MainActivity.class(舉例),我們這里先看一下遍歷的規(guī)則则吟,再來看遍歷里干了些什么槐臀,首先這里的判斷依據(jù)是根據(jù)findState.clazz!=null
.每次執(zhí)行完findUsingReflectionInSingleClass(findState);
方法都會執(zhí)行findState.moveToSuperclass
方法。
void moveToSuperclass() {
//如果配置忽略父類方法則不檢查父類方法
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
這里可以看到氓仲,方法的作用就是向上遍歷父Class水慨,可以通過配置不向上遍歷父Class,但是默認是會先檢查父Class,而且這里需要注意的一個點敬扛,向上遍歷的終點是檢查到Class是以“java.”"javax.""android."開頭的晰洒,也就是說對于系統(tǒng)源碼內(nèi)的class是不會檢查的,這時class變成null啥箭,整個循環(huán)也就結(jié)束了谍珊。所以這里又可以解釋我們的一個疑惑,默認EventBus是會檢查父類中的訂閱方法的急侥。
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
//通過注釋其實也可以看到EventBus團隊對于反射性能都考慮砌滞,所以用getDeclaredMethods而不是getMethods
//獲取都不包括父類和接口都方法,包括私有都坏怪,
//疑問點1
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
//方法必須是Public贝润,不能是static,abstract,生成索引時會出問題
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//獲取方法都參數(shù)
Class<?>[] parameterTypes = method.getParameterTypes();
//參數(shù)個數(shù)=1
if (parameterTypes.length == 1) {
//方法是用@Subscribe注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
//獲取第一個參數(shù)都Class,也就是事件類都class
Class<?> eventType = parameterTypes[0];
// 檢查eventType決定是否訂閱铝宵,通常訂閱者不能有多個eventType相同的訂閱方法
//疑問點2
if (findState.checkAdd(method, eventType)) {
//獲得Thread類型
ThreadMode threadMode = subscribeAnnotation.threadMode();
//ArrayList加入一個SubscriberMethod對象
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
接下來看到這個獲得訂閱的方法打掘。這里注釋寫的都比較全了這里有幾個疑問點是需要我們了解的:
疑問點1
可以看到這里使用了getDeclaredMethods而沒有使用getMethods,這里通過注釋我們可以看到捉超,這里EventBus團隊出于對于反射性能的考慮胧卤,使用getDeclaredMethods
代替getMethods
方法,這里可能有疑問了拼岳,這樣使用為什么能提高性能枝誊?
首先我們來大概解釋一下兩個方法的區(qū)別吧:
public Method[] getMethods()返回某個類的所有公用(public)方法包括其繼承類的公用方法,當(dāng)然也包括它所實現(xiàn)接口的方法惜纸。
public Method[] getDeclaredMethods()對象表示的類或接口聲明的所有方法叶撒,包括公共、保護耐版、默認(包)訪問和私有方法祠够,但不包括繼承的方
法。當(dāng)然也包括它所實現(xiàn)接口的方法粪牲。
起初我也在疑惑為什么這樣能夠提升性能古瓤,直達看到了一篇博客,這篇博客也是對EventBus的源碼的講解,中間提到了的關(guān)于這里性能提升的講解落君,這里也是EventBus在完善一個issue的解決方案穿香。這里大概解釋一下:
可以看到這兩個方法比較顯著的區(qū)別是,getDeclaredMethods
只會獲取當(dāng)前類的所有方法绎速,而getMethods
會獲取所有公用方法皮获,包括繼承的。而前面也提到纹冤,EventBus在查找完這里后洒宝,會調(diào)用findState.moveToSuperclass()
,向上繼續(xù)查詢父類的方法萌京,所以這里使用getMethods
會重復(fù)查詢父類的方法雁歌。
疑問點2
findState.checkAdd(method, eventType)
這層檢查是什么作用的?
這里提出兩個特殊場景(一般應(yīng)該也不會有人這樣寫吧):
1.一個類中存在兩個方法名不同枫夺,但是是同一個Event類型的訂閱方法将宪,EventBus會怎樣處理?
2.子類和父類存在相同方法名和Event類型的訂閱方法橡庞,EventBus會怎樣處理较坛?
這個方法的作用就是處理上面這兩種情況的,所以還是需要我們追究一下這里的源碼實現(xiàn):
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
//HashMap,一般一個Event只有一個方法
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
//不存在該參數(shù)類型的方法扒最,直接添加到訂閱者
return true;
} else {
if (existing instanceof Method) {
//存在相同的參數(shù)類型丑勤,代表參數(shù)類型相同,但可能方法名不同吧趣,或者方法名也相同(父類中的被重寫的方法)
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
這里可以看到anyMethodByEventType
是一個HashMap,如果當(dāng)前Event的類型是原來沒有過的法竞,直接返回true,加入到anyMethodByEventType
中强挫。而當(dāng)這個參數(shù)類型已經(jīng)被加入過了岔霸,存在兩種情況,也就是剛才已經(jīng)提到的兩種情況俯渤,代表參數(shù)類型相同呆细,但可能方法名不同,或者方法名也相同(父類中的被重寫的方法)八匠,這時就要進行checkAddWithMethodSignature
方法的檢查絮爷。
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class<?> methodClass = method.getDeclaringClass();
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
//methodClassOld = null,說明時方法名不同的情況梨树,直接返回true坑夯,會加入訂閱。
//返回true
// Only add if not already found in a sub class
return true;
} else {
//methodClass一定是methodClassOld的父類抡四,因為是向上遍歷的柜蜈,所以父類的方法不會被加入訂閱
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
可以看到這里同樣是一個HashMap類型的subscriberClassByMethodKey
仗谆,而key值對應(yīng)的就是以“方法名>EventType名”。
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
第一種情況跨释,一個類中存在兩個方法名不同胸私,但是是同一個Event類型的訂閱方法,這時由于方法名不同鳖谈,所有key值不同,所有每次methodClassOld = null
阔涉,所以接下來的判斷條件里缆娃,會直接返回true。加入這個訂閱方法瑰排。
第二種情況贯要,子類和父類存在相同方法名和Event類型的訂閱方法(也就是重寫),這時由于方法名相同椭住,Event類型也相同崇渗,所以每次methodClassOld != null
,這時就要看第二個判斷條件京郑,methodClassOld.isAssignableFrom(methodClass),這里我們就要明白isAssignableFrom
函數(shù)的作用宅广。
class1.isAssignableFrom(class2) class2是不是class1的子類或者子接口
這里我們就會發(fā)現(xiàn)在這種情況下,methodClassOld一定是methodClass的子類些举。因為從前面的分析我們知道跟狱,EventBus是從子類向上遍歷的過程,所以先加入的肯定是子類的方法户魏,后加入的肯定是父類的方法驶臊,所以methodClassOld.isAssignableFrom(methodClass)
,這個判斷肯定是false叼丑,所以最終我們在這種情況下會返回false关翎。最終也就是說明子類重寫的方法會加入訂閱,但是父類的被重寫的方法不會被加入訂閱鸠信。
向上回溯到register方法
public void register(Object subscriber) {
//獲得訂閱者對應(yīng)的Class,MainActivity.class
Class<?> subscriberClass = subscriber.getClass();
//找到所有的訂閱的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
到這里我們已經(jīng)分析完subscriberMethodFinder.findSubscriberMethods(subscriberClass)
中反射到方式獲取所有的訂閱方法了纵寝。可以看到症副,在獲得list后店雅,會進行一次遍歷。執(zhí)行subscribe
方法贞铣。
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//每次都會new了一個Subscription對象闹啦,subsciber代表我們的訂閱者MainActivity.class, subscriberMethod代表其中的一個訂閱的方法。
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//判斷是否有以Event.class為key
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//為null說明不存在該參數(shù)類型的方法沒有被訂閱過
if (subscriptions == null) {
//new 一個
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//subscriptions不為null的情況是指存在多個訂閱這個Event的類辕坝。
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
//如果長度不為0代表該事件有大于一個訂閱者窍奋,或一個訂閱中中有多個訂閱方法訂閱這個Event,相同參數(shù)名的方法
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
//按優(yōu)先級加入
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//粘性事件相關(guān),后面博客會分析
//下面是粘性事件的代碼
}
這里就要提到EventBus中我認為最為重要的兩個Map中的第一個Map——subscriptionsByEventType琳袄,到后來看完EventBus的源碼后你會發(fā)現(xiàn)理解這兩個Map基本上就理解了EventBus的基本原理江场。
首先來看第一個Map的數(shù)據(jù)結(jié)構(gòu)。
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
}
可以看到這里map是以class為key,CopyOnWriteArrayList<Subscription>為value的HashMap,這里要強調(diào)一下是HashMap窖逗,后面會解釋為什么要強調(diào)址否。(HashMap的底層原理?)
接下來我們根據(jù)上面的源碼來理解這個Map的作用碎紊。
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
首先嘗試從subscriptionsByEventType中嘗試是否已經(jīng)存在過這個EventType.
if (subscriptions == null) {
//new 一個
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//subscriptions不為null的情況是指方法名不同佑附,但是參數(shù)類型相同。也就是剛才提到的兩種情況中的第一種
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
當(dāng)不存在仗考,處理就比較簡單音同,new一個CopyOnWriteArrayList,并且在subscriptionsByEventType
中加入一條數(shù)據(jù)秃嗜。
當(dāng)存在這個EventType权均,則這時就要判斷一下subscriptions.contains(newSubscription)
是否已經(jīng)注冊過這個類型。這里我們要詳細理解一下锅锨。
如何判斷一個類已經(jīng)注冊過了叽赊。
//每次都會new了一個Subscription對象,subsciber代表我們的訂閱者MainActivity.class, subscriberMethod代表其中的一個訂閱的方法橡类。
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
而我們知道subscriptions
是一個CopyOnWriteArrayList蛇尚。這時我們就要看一下CopyOnWriteArrayList
的源碼了,contain()
最后會走到indexOf()
方法顾画。
public boolean contains(Object var1) {
Object[] var2 = this.getArray();
return indexOf(var1, var2, 0, var2.length) >= 0;
}
//var0 是參數(shù)
//var1 是CopyOnWriteArrayList內(nèi)部的數(shù)組
//var2 是0
//var3 是數(shù)組的長度
private static int indexOf(Object var0, Object[] var1, int var2, int var3) {
int var4;
if(var0 == null) {
for(var4 = var2; var4 < var3; ++var4) {
if(var1[var4] == null) {
return var4;
}
}
} else {
for(var4 = var2; var4 < var3; ++var4) {
//是通過equal判斷
if(var0.equals(var1[var4])) {
return var4;
}
}
}
return -1;
}
這里
可以看到取劫,如果判斷這個是否已經(jīng)訂閱過了,最后會通過equal方法判斷研侣,哪理所當(dāng)然Subscription
肯定重寫了equal方法谱邪。
@Override
public boolean equals(Object other) {
if (other instanceof Subscription) {
Subscription otherSubscription = (Subscription) other;
//==比較的是內(nèi)存地址,所以如果兩個類地址不同庶诡,也不相同(棧內(nèi)存在兩個MainActivity),
//是否存在相同的訂閱類名惦银,方法名,參數(shù)類型名(同一個Activity中存在兩個不同的方法訂閱這個Event)末誓。
return subscriber == otherSubscription.subscriber
&& subscriberMethod.equals(otherSubscription.subscriberMethod);
} else {
return false;
}
}
對于兩個
最終這里還會比較SubscriberMethod
重寫的equal方法扯俱,最后會比較是否存在相同的訂閱類名,方法名喇澡,參數(shù)類型名迅栅。。這里其實就是我們剛才討論的兩種特殊情況中的第一種晴玖,當(dāng)存在兩個EventType相同读存,但是方法名不同的情況为流。如果一個類中存在多個方法名相同,參數(shù)類型相同的方法让簿,則會拋異常敬察。
int size = subscriptions.size();
//如果長度不為0代表有大于1個的不同訂閱者,或者方法名尔当,相同參數(shù)名的方法
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
//按優(yōu)先級加入
subscriptions.add(i, newSubscription);
break;
}
}
當(dāng)沒有拋異常莲祸,則會按照優(yōu)先級進行加入,若沒有定義優(yōu)先級椭迎,則末尾加入虫给。到這對于第一個Map我們其實已經(jīng)有了一個比較深刻的理解
第一個Map的作用:保存對于一個Event所有的訂閱者和訂閱方法,
這里就放上一張圖吧侠碧,個人感覺非常有用。
//維持當(dāng)前訂閱者訂閱的所有Event
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
緊接著缠黍,我們會看到EventBus中另一個重要的Map-typesBySubscriber
,和剛才一樣弄兜,看一下數(shù)據(jù)結(jié)構(gòu)。
private final Map<Object, List<Class<?>>> typesBySubscriber;
typesBySubscriber = new HashMap<>();
不出意外瓷式,還是HashMap,這里的邏輯就比較好理解了贸典,key對應(yīng)的是訂閱者類型,Value對應(yīng)的是一個List<EventType.class>廊驼。
第二個Map的作用:保存訂閱者和訂閱者中的所有的訂閱Event。
疑惑
這里其實就要解釋我們的一個疑惑了妒挎,當(dāng)棧內(nèi)存在多個相同的MainActivity時绳锅,Eventbus如何訂閱的酝掩?
這里就和我們兩個Map有關(guān)了,首先第一個Map中對于是否重復(fù)訂閱使用的
contain
函數(shù)進行判斷期虾,最后包含==的判斷原朝,也就是內(nèi)存地址的判斷,不同的>Activity對象镶苞,內(nèi)存地址肯定不同。
其次第二個Map,是一個HashMap宾尚,key就是我們的MainActivity谢澈,是一個Object類型御板,那么多個MainActivity時,加入第二個HashMap怠肋,為什么能區(qū)分哪?因為hashCode不同笙各,根據(jù)HashMap的原理,不同的MainActivity的hashcode不同数尿,當(dāng)然可以都加入了惶楼。
后面的代碼就是粘性事件相關(guān)的代碼邏輯了,后面的博客我們會分析歼捐。
總結(jié)
這里我們來總結(jié)一下注冊的流程:
1.獲取訂閱類里的所有的訂閱的方法,其中訂閱類父類的方法也會被記錄贷盲,重寫的方法不會被記錄剥扣,方法名不同,參數(shù)類型相同的方法會被記錄
2.填充兩個Map朦乏,第一個Map記錄訂閱了Event的所有訂閱者和其方法,第二個Map記錄了所有的訂閱者和其訂閱的所有Event吃引。