前言
在寫這篇源碼解析到一半時(shí)發(fā)現(xiàn)EventBus有很多高級用法是不能直接忽略的,于是回過頭來寫了EventBus高級用法這一篇,傳送門:Android開源庫——EventBus高級用法
這篇主要通過源碼分析來了解EventBus的實(shí)現(xiàn)原理,EventBus的版本為3.1.1,主要分為三部分,也就是實(shí)現(xiàn)的三個(gè)步驟
- 注冊訂閱者
- 事件發(fā)布
- 反注冊訂閱者
話不多說,馬上開始
源碼分析
注冊訂閱者
首先我們從EventBus注冊訂閱者的這一句入手
EventBus.getDefault().register(this);
getDefault()表面意思大概是獲取一個(gè)EventBus的實(shí)例,看一下源碼
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
一個(gè)DoubleCheck的單例模式獲取到實(shí)例,能高效的面對并發(fā)獲取實(shí)例的情況
再看一下EventBus的構(gòu)造方法
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}
默認(rèn)的構(gòu)造方法又調(diào)用參數(shù)為EventBusBuilder的構(gòu)造方法,構(gòu)造出EventBus的實(shí)例,這里使用的是默認(rèn)的一個(gè)EventBusBuilder,從名字就可以看出EventBusBuilder采用的是Builder模式,個(gè)性化配置EventBus的各項(xiàng)參數(shù)保存在Builder中,build時(shí)構(gòu)造EventBus并將各項(xiàng)配置應(yīng)用于EventBus
/** Builds an EventBus based on the current configuration. */
public EventBus build() {
return new EventBus(this);
}
接下來看register()
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
// 獲取訂閱者的訂閱方法并用List封裝
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
// 逐個(gè)訂閱
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
register()接收參數(shù)為Object類型的訂閱者,通常也就是代碼中Activity和Fragment的實(shí)例this。subscriberMethodFinder是EventBus的一個(gè)成員,可以看作是一個(gè)訂閱方法查找器,是在剛剛的EventBus構(gòu)造方法通過EventBusBuilder的一些參數(shù)構(gòu)造出來的。調(diào)用findSubscriberMethods方法,傳入訂閱者的Class對象,字面意思是找出訂閱者中所有的訂閱方法,用一個(gè)List集合來接收,看看是不是
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
// 使用反射方式獲取
subscriberMethods = findUsingReflection(subscriberClass);
} else {
// 使用SubscriberIndex方式獲取
subscriberMethods = findUsingInfo(subscriberClass);
}
// 若訂閱者中沒有訂閱方法,則拋異常
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
// 緩存訂閱者的訂閱方法List
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
METHOD_CACHE是一個(gè)Map,以訂閱者的Class對象為key,訂閱者中的訂閱方法List為value,緩存了注冊過的訂閱方法,如果有緩存則返回返回緩存,如果沒有則繼續(xù)往下執(zhí)行。這里看到ignoreGeneratedIndex這個(gè)屬性,意思為是否忽略生成index,是在構(gòu)造SubscriberMethodFinder通過EventBusBuilder的同名屬性賦值的,默認(rèn)為false,當(dāng)為true時(shí),表示以反射的方式獲取訂閱者中的訂閱方法,當(dāng)為false時(shí),則以Subscriber Index的方式獲取。接下來分別分析這兩種方式。
首先是ignoreGeneratedIndex為true時(shí),追蹤源碼
private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
// 創(chuàng)建并初始化FindState對象
FindState findState = prepareFindState();
// findState與subscriberClass關(guān)聯(lián)
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 使用反射的方式獲取單個(gè)類的訂閱方法
findUsingReflectionInSingleClass(findState);
// 使findState.clazz指向父類的Class,繼續(xù)獲取
findState.moveToSuperclass();
}
// 返回訂閱者極其父類的訂閱方法List,并釋放資源
return getMethodsAndRelease(findState);
}
創(chuàng)建一個(gè)FindState對象來輔助獲取訂閱方法,這里只看反射獲取的關(guān)鍵代碼:findUsingReflectionInSingleClass
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
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等修飾的方法
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
// 獲取訂閱方法的所有參數(shù)
Class<?>[] parameterTypes = method.getParameterTypes();
// 訂閱方法只能有一個(gè)參數(shù),否則忽略
if (parameterTypes.length == 1) {
// 獲取注解
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
// 獲取第一個(gè)參數(shù)
Class<?> eventType = parameterTypes[0];
// 檢查eventType決定是否訂閱,通常訂閱者不能有多個(gè)eventType相同的訂閱方法
if (findState.checkAdd(method, eventType)) {
// 獲取線程模式
ThreadMode threadMode = subscribeAnnotation.threadMode();
// 添加訂閱方法進(jìn)List
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");
}
}
}
代碼也不難懂,經(jīng)過修飾符、參數(shù)個(gè)數(shù)、是否有注解、和訂閱者是否有eventType相同的方法幾層條件的篩選,最終將訂閱方法添加進(jìn)findState的subscriberMethods這個(gè)List中。來到這里,不得不說EventBus真是非常強(qiáng)大,它不僅僅獲取當(dāng)前類的訂閱方法,還會(huì)獲取它所有父類的訂閱方法
// 使findState.clazz指向父類的Class,繼續(xù)獲取
findState.moveToSuperclass();
通過改變尋找狀態(tài)對象findState的clazz屬性,使之指向父類的Class,來遍歷出當(dāng)前類整個(gè)家族的訂閱方法,最終獲取到所有的訂閱方法后返回List并釋放資源。
接下來就看看ignoreGeneratedIndex為false的情況
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
// 獲取當(dāng)前clazz對應(yīng)的SubscriberInfo
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
// 通過SubscriberInfo獲取閱方法數(shù)組
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
// 逐個(gè)添加進(jìn)findState.subscriberMethods
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
// 若SubscriberInfo為空,則采用反射方式獲取
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
跟反射方式的findUsingReflection的首尾有點(diǎn)類似,不同的是它是通過SubscriberInfo這個(gè)類來獲取訂閱方法的,那么SubscriberInfo對象是怎么獲取的呢,那么同樣只看關(guān)鍵代碼:getSubscriberInfo
private SubscriberInfo getSubscriberInfo(FindState findState) {
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
if (findState.clazz == superclassInfo.getSubscriberClass()) {
return superclassInfo;
}
}
if (subscriberInfoIndexes != null) {
for (SubscriberInfoIndex index : subscriberInfoIndexes) {
// 通過SubscriberIndex獲取findState.clazz對應(yīng)的SubscriberInfo
SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
if (info != null) {
return info;
}
}
}
return null;
}
這時(shí)候主角出現(xiàn)了,我們看subscriberInfoIndexes,它是一個(gè)List,類型為Subscriber Index,意思訂閱者索引,也是這種方式的重要角色。追蹤它的出處
SubscriberMethodFinder(List<SubscriberInfoIndex> subscriberInfoIndexes, boolean strictMethodVerification,
boolean ignoreGeneratedIndex) {
this.subscriberInfoIndexes = subscriberInfoIndexes;
this.strictMethodVerification = strictMethodVerification;
this.ignoreGeneratedIndex = ignoreGeneratedIndex;
}
是在構(gòu)造SubscriberMethodFinder時(shí)賦值的,而SubscriberMethodFinder是在EventBus的構(gòu)造方法中通過EventBusBuilder的參數(shù)構(gòu)造的
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
繼續(xù)追蹤EventBusBuilder中的subscriberInfoIndexes,發(fā)現(xiàn)如下代碼
/** Adds an index generated by EventBus' annotation preprocessor. */
public EventBusBuilder addIndex(SubscriberInfoIndex index) {
if(subscriberInfoIndexes == null) {
subscriberInfoIndexes = new ArrayList<>();
}
subscriberInfoIndexes.add(index);
return this;
}
通過注釋可知,Subscriber Index是由EventBus注解處理器生成的,那么EventBus注解處理器是什么呢?如果你想用索引的方式來獲取訂閱方法,這時(shí)候就很有必要看一下官方文檔,它教你如何使用Subscriber Index,非常重要
EventBus Subscriber Index 使用教程
看完文檔,我們知道Subscriber Index是EventBus 3上的新技術(shù),所以這里也建議還沒學(xué)習(xí)過EventBus的可以跳過2.X之前的版本直接學(xué)習(xí)最新版本。
關(guān)于EventBus的Subscriber Index技術(shù)的特點(diǎn),翻譯一下官方解釋:
It is an optional optimization to speed up initial subscriber registration.
Subscriber Index是一個(gè)可選的優(yōu)化技術(shù),用來加速初始化訂閱者注冊。
The subscriber index can be created during build time using the EventBus annotation processor. While it is not required to use an index, it is recommended on Android for best performance.
Subscriber Index在編譯時(shí)使用EventBus注解處理器創(chuàng)建,雖然沒有規(guī)定必須使用它,但是官方推薦使用這種方式,因?yàn)樗贏ndroid上有著最佳的性能。
回到代碼中來,findState.subscriberInfo始終指向當(dāng)前正在獲取訂閱方法的訂閱者的subscriberInfo,看關(guān)鍵代碼
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
通過getSubscriberMethods()獲取到訂閱方法數(shù)組,然后與反射方式類似地,逐個(gè)將訂閱方法添加進(jìn)findState的subscriberMethods這個(gè)List中,返回該List并釋放資源。
// 逐個(gè)添加進(jìn)findState.subscriberMethods
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
到此,兩種方式講解完畢。無論通過哪種方式獲取,獲取到訂閱方法List之后,接下來是真正訂閱的過程,回到register()中看代碼
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
遍歷逐個(gè)訂閱,看subscribe方法
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
// 創(chuàng)建Subscription封裝訂閱者和訂閱方法信息
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
// 根據(jù)事件類型從subscriptionsByEventType這個(gè)Map中獲取Subscription集合
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
// 若Subscription集合為空,創(chuàng)建并put進(jìn)Map中
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 若集合中已包含該Subscription則拋異常
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
// 按照優(yōu)先級插入Subscription
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// typesBySubscriber與subscriptionsByEventType類似
// 用來存放訂閱者中的事件類型
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
// 訂閱方法是否設(shè)置黏性模式
if (subscriberMethod.sticky) {
// 是否設(shè)置了事件繼承
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();
// 判斷當(dāng)前事件類型是否為黏性事件或者其子類
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
// 執(zhí)行設(shè)置了sticky模式的訂閱方法
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
方便起見,關(guān)鍵代碼都附上了注釋,簡單講解一下關(guān)鍵角色:
- subscriptionsByEventType:以事件類型為key,擁有相同事件類型的訂閱方法List為value,存放所有的訂閱方法。
- typesBySubscriber:以訂閱者為key,訂閱者訂閱的所有事件類型List為value,存放所有的事件類型。
在這里出現(xiàn)了stickyEvent(黏性事件),接下來會(huì)在事件分布中講解它的作用,以上便是注冊訂閱者的過程。
事件發(fā)布
一般的事件發(fā)布方式
EventBus.getDefault().post(new UpdateUIEvent());
這里我們看post()
/** Posts the given event to the event bus. */
public void post(Object event) {
// 獲取當(dāng)前線程的posting狀態(tài)
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
// 將事件添加進(jìn)當(dāng)前線程的事件隊(duì)列
eventQueue.add(event);
// 判斷當(dāng)前線程是否正在發(fā)布事件
if (!postingState.isPosting) {
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
// 取消發(fā)布狀態(tài)沒有重置,拋異常
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
PostingThreadState(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
EventBus用ThreadLocal存儲(chǔ)每個(gè)線程的PostingThreadState,一個(gè)存儲(chǔ)了事件發(fā)布狀態(tài)的類,當(dāng)post一個(gè)事件時(shí),添加到事件隊(duì)列末尾,等待前面的事件發(fā)布完畢后再拿出來發(fā)布,這里看事件發(fā)布的關(guān)鍵代碼PostingThreadState()
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
// 發(fā)布事件
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
// 發(fā)布事件
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));
}
}
}
代碼也非常簡單,首先看eventInheritance這個(gè)屬性,是否開啟事件繼承,若是,找出發(fā)布事件的所有父類,也就是lookupAllEventTypes(),然后遍歷每個(gè)事件類型進(jìn)行發(fā)布,若不是,則直接發(fā)布該事件。如果需要發(fā)布的事件沒有找到任何匹配的訂閱信息,則發(fā)布一個(gè)NoSubscriberEvent事件。這里只看發(fā)布事件的關(guān)鍵代碼postSingleEventForEventType()
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 根據(jù)事件類型找出相關(guān)的訂閱信息
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
// 發(fā)布事件到具體的訂閱者
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;
}
來到這里,開始根據(jù)事件類型匹配出訂閱信息,如果該事件有訂閱信息,則執(zhí)行postToSubscription(),發(fā)布事件到每個(gè)訂閱者,返回true,若沒有,則發(fā)回false。繼續(xù)追蹤發(fā)布事件到具體訂閱者的代碼
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
// 訂閱線程跟隨發(fā)布線程
case POSTING:
// 訂閱線程和發(fā)布線程相同,直接訂閱
invokeSubscriber(subscription, event);
break;
// 訂閱線程為主線程
case MAIN:
if (isMainThread) {
// 發(fā)布線程和訂閱線程都是主線程,直接訂閱
invokeSubscriber(subscription, event);
} else {
// 發(fā)布線程不是主線程,訂閱線程切換到主線程訂閱
mainThreadPoster.enqueue(subscription, event);
}
break;
// 訂閱線程為后臺線程
case BACKGROUND:
if (isMainThread) {
// 發(fā)布線程為主線程,切換到后臺線程訂閱
backgroundPoster.enqueue(subscription, event);
} else {
// 發(fā)布線程不為主線程,直接訂閱
invokeSubscriber(subscription, event);
}
break;
// 訂閱線程為異步線程
case ASYNC:
// 使用線程池線程訂閱
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
看到四種線程模式,我們回顧一下上一篇的內(nèi)容
- POSTING:事件發(fā)布在什么線程,就在什么線程訂閱。
- MAIN:無論事件在什么線程發(fā)布,都在主線程訂閱。
- BACKGROUND:如果發(fā)布的線程不是主線程,則在該線程訂閱,如果是主線程,則使用一個(gè)單獨(dú)的后臺線程訂閱。
- ASYNC:在非主線程和發(fā)布線程中訂閱。
訂閱者四種線程模式的特點(diǎn)對應(yīng)的就是以上代碼,簡單來講就是訂閱者指定了在哪個(gè)線程訂閱事件,無論發(fā)布者在哪個(gè)線程,它都會(huì)將事件發(fā)不到訂閱者指定的線程。這里我們繼續(xù)看實(shí)現(xiàn)訂閱者的方法
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
到這里我們終于看到了Java的API,有種撥開云霧見月明的感覺
subscription.subscriberMethod.method.invoke(subscription.subscriber, event)
訂閱者接收到了事件,調(diào)用訂閱方法,傳入發(fā)布的事件作為參數(shù),至此,事件發(fā)布過程就結(jié)束了。
反注冊訂閱者
先看反注冊的代碼
EventBus.getDefault().unregister(this);
跟蹤unregister()
/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
注冊過程我們就知道typesBySubscriber是保存訂閱者的所有訂閱事件類型的一個(gè)Map,這里根據(jù)訂閱者拿到訂閱事件類型List,然后逐個(gè)取消訂閱,最后typesBySubscriber移除該訂閱者,。這里只需要關(guān)注它是如果取消訂閱的,跟蹤unsubscribeByEventType()
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
subscriptionsByEventType是存儲(chǔ)事件類型對應(yīng)訂閱信息的Map,代碼邏輯非常清晰,找出某事件類型的訂閱信息List,遍歷訂閱信息,將要取消訂閱的訂閱者和訂閱信息封裝的訂閱者比對,如果是同一個(gè),則說明該訂閱信息是將要失效的,于是將該訂閱信息移除。
到這里,反注冊訂閱者的過程就講解完畢啦。
總結(jié)
回顧一下EventBus的三個(gè)步驟
- 注冊訂閱者
- 事件發(fā)布
- 反注冊訂閱者
通過分析EventBus源碼,發(fā)現(xiàn)注冊的過程最為復(fù)雜,發(fā)布次之,反注冊最簡單,但這也是相對而言,總的來講,EventBus這個(gè)庫的源碼沒有太多晦澀難懂的地方,算是非常好理解的,這里不得不佩服EvenBus的作者們,整個(gè)庫的架構(gòu)、邏輯設(shè)計(jì),接口設(shè)計(jì),小到方法和變量的命名,都顯得非常優(yōu)雅易懂,相比之下,曾閱讀過的Glide的源碼就顯得......哈哈,不過這兩個(gè)庫的代碼量也不是同一個(gè)級別的,不能簡單地直接比較。
好了,EventBus的源碼解析到這就結(jié)束了,想進(jìn)一步了解EventBus的朋友可以親自去閱讀源碼,畢竟自己親身去探索,比聽別人的理解更深。這里借用Linus的一句話,與大家共勉
Read the fucking source code