Android事件總線(二)EventBus3.0源碼解析
1.構(gòu)造函數(shù)
當(dāng)我們要調(diào)用EventBus的功能時(shí),比如注冊(cè)或者發(fā)送事件,總會(huì)調(diào)用EventBus.getDefault()來(lái)獲取EventBus實(shí)例:
public static EventBus getDefault() { if (defaultInstance == null) { synchronized (EventBus.class) { if (defaultInstance == null) { defaultInstance = new EventBus(); } } } return defaultInstance; }
很明顯這是一個(gè)單例模式,采用了雙重檢查模式 (DCL)。
接下來(lái)看看new EventBus()做了什么:
public EventBus() { this(DEFAULT_BUILDER); }
這里DEFAULT_BUILDER是默認(rèn)的EventBusBuilder,用來(lái)構(gòu)造EventBus:
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
this調(diào)用了EventBus另一個(gè)構(gòu)造函數(shù):
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; }
2.訂閱者注冊(cè)
獲取到EventBus后,便可以將訂閱者注冊(cè)到EventBus中,下面來(lái)看一下register方法:
public void register(Object subscriber) { Class<?> subscriberClass = subscriber.getClass(); // 用 subscriberMethodFinder 提供的方法,找到在 subscriber 這個(gè)類里面訂閱的內(nèi)容。 List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }
查找訂閱方法
findSubscriberMethods找出一個(gè)SubscriberMethod的集合,也就是傳進(jìn)來(lái)的訂閱者所有的訂閱的方法,接下來(lái)遍歷訂閱者的訂閱方法來(lái)完成訂閱者的訂閱操作。對(duì)于SubscriberMethod(訂閱方法)類中,主要就是用保存訂閱方法的Method對(duì)象、線程模式、事件類型、優(yōu)先級(jí)、是否是粘性事件等屬性。下面就來(lái)看一下findSubscriberMethods方法:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) { //從緩存中獲取SubscriberMethod集合 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } //ignoreGeneratedIndex屬性表示是否忽略注解器生成的MyEventBusIndex if (ignoreGeneratedIndex) { //通過(guò)反射獲取subscriberMethods subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); } //在獲得subscriberMethods以后,如果訂閱者中不存在@Subscribe注解并且為public的訂閱方法,則會(huì)拋出異常。 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; } }
首先從緩存中查找,如果找到了就立馬返回。如果緩存中沒有的話,則根據(jù) ignoreGeneratedIndex 選擇如何查找訂閱方法,ignoreGeneratedIndex屬性表示是否忽略注解器生成的MyEventBusIndex。不了解MyEventBusIndex的同學(xué)可以查看【Bugly干貨分享】老司機(jī)教你 “飆” EventBus 3這篇文章。最后,找到訂閱方法后,放入緩存,以免下次繼續(xù)查找。ignoreGeneratedIndex 默認(rèn)就是false,可以通過(guò)EventBusBuilder來(lái)設(shè)置它的值。我們?cè)陧?xiàng)目中經(jīng)常通過(guò)EventBus單例模式來(lái)獲取默認(rèn)的EventBus對(duì)象,也就是ignoreGeneratedIndex為false的情況,這種情況調(diào)用了findUsingInfo方法:
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { //獲取訂閱者信息,沒有配置MyEventBusIndex返回null findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); } } } else { //通過(guò)反射來(lái)查找訂閱方法 findUsingReflectionInSingleClass(findState); } findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }
通過(guò)getSubscriberInfo方法來(lái)獲取訂閱者信息。在我們開始查找訂閱方法的時(shí)候并沒有忽略注解器為我們生成的索引MyEventBusIndex,如果我們通過(guò)EventBusBuilder配置了MyEventBusIndex,便會(huì)獲取到subscriberInfo,調(diào)用subscriberInfo的getSubscriberMethods方法便可以得到訂閱方法相關(guān)的信息,這個(gè)時(shí)候就不在需要通過(guò)注解進(jìn)行獲取訂閱方法。如果沒有配置MyEventBusIndex,便會(huì)執(zhí)行findUsingReflectionInSingleClass方法,將訂閱方法保存到findState中。最后再通過(guò)getMethodsAndRelease方法對(duì)findState做回收處理并反回訂閱方法的List集合。
對(duì)于MyEventBusIndex的配置它是一個(gè)可選項(xiàng),所以在這里就不在進(jìn)行詳細(xì)的介紹,下面就來(lái)看一下findUsingReflectionInSingleClass的執(zhí)行過(guò)程:
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(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); if (subscribeAnnotation != null) { Class<?> eventType = parameterTypes[0]; if (findState.checkAdd(method, eventType)) { ThreadMode threadMode = subscribeAnnotation.threadMode(); 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"); } } }
在這里主要是使用了Java的反射和對(duì)注解的解析。首先通過(guò)反射來(lái)獲取訂閱者中所有的方法。并根據(jù)方法的類型,參數(shù)和注解來(lái)找到訂閱方法。找到訂閱方法后將訂閱方法相關(guān)信息保存到FindState當(dāng)中。
訂閱者的注冊(cè)過(guò)程
在查找完所有的訂閱方法以后便開始對(duì)所有的訂閱方法進(jìn)行注冊(cè):
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class<?> eventType = subscriberMethod.eventType; //根據(jù)訂閱者和訂閱方法構(gòu)造一個(gè)訂閱事件 Subscription newSubscription = new Subscription(subscriber, subscriberMethod); //獲取當(dāng)前訂閱事件中Subscription的List集合 CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType); //該事件對(duì)應(yīng)的Subscription的List集合不存在,則重新創(chuàng)建并保存在subscriptionsByEventType中 if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { //訂閱者已經(jīng)注冊(cè)則拋出EventBusException if (subscriptions.contains(newSubscription)) { throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType); } } //遍歷訂閱事件,找到比subscriptions中訂閱事件小的位置,然后插進(jìn)去 int size = subscriptions.size(); for (int i = 0; i <= size; i++) { if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { subscriptions.add(i, newSubscription); break; } } //通過(guò)訂閱者獲取該訂閱者所訂閱事件的集合 List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } //將當(dāng)前的訂閱事件添加到subscribedEvents中 subscribedEvents.add(eventType); if (subscriberMethod.sticky) { if (eventInheritance) { //粘性事件的處理 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); } } }
訂閱的代碼主要就做了兩件事,第一件事是將我們的訂閱方法和訂閱者封裝到subscriptionsByEventType和typesBySubscriber中,subscriptionsByEventType是我們投遞訂閱事件的時(shí)候,就是根據(jù)我們的EventType找到我們的訂閱事件,從而去分發(fā)事件,處理事件的;typesBySubscriber在調(diào)用unregister(this)的時(shí)候,根據(jù)訂閱者找到EventType,又根據(jù)EventType找到訂閱事件,從而對(duì)訂閱者進(jìn)行解綁。第二件事,如果是粘性事件的話,就立馬投遞、執(zhí)行。
3.事件的發(fā)送
在獲取到EventBus對(duì)象以后,可以通過(guò)post方法來(lái)進(jìn)行對(duì)事件的提交:
public void post(Object event) { //PostingThreadState保存著事件隊(duì)列和線程狀態(tài)信息 PostingThreadState postingState = currentPostingThreadState.get(); //獲取事件隊(duì)列,并將當(dāng)前事插入到事件隊(duì)列中 List<Object> eventQueue = postingState.eventQueue; eventQueue.add(event); if (!postingState.isPosting) { postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper(); postingState.isPosting = true; if (postingState.canceled) { throw new EventBusException("Internal error. Abort state was not reset"); } try { //處理隊(duì)列中的所有事件 while (!eventQueue.isEmpty()) { postSingleEvent(eventQueue.remove(0), postingState); } } finally { postingState.isPosting = false; postingState.isMainThread = false; } } }
首先從PostingThreadState對(duì)象中取出事件隊(duì)列,然后再將當(dāng)前的事件插入到事件隊(duì)列當(dāng)中。最后將隊(duì)列中的事件依次交由postSingleEvent方法進(jìn)行處理,并移除該事件。來(lái)看看postSingleEvent方法里做了什么:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass(); boolean subscriptionFound = false; //eventInheritance表示是否向上查找事件的父類,默認(rèn)為true 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); } //找不到該事件時(shí)的異常處理 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表示是否向上查找事件的父類,它的默認(rèn)值為true,可以通過(guò)在EventBusBuilder中來(lái)進(jìn)行配置。當(dāng)eventInheritance為true時(shí),則通過(guò)lookupAllEventTypes找到所有的父類事件并存在List中,然后通過(guò)postSingleEventForEventType方法對(duì)事件逐一處理,接下來(lái)看看postSingleEventForEventType方法:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) { CopyOnWriteArrayList<Subscription> subscriptions; //取出該事件對(duì)應(yīng)的Subscription集合 synchronized (this) { subscriptions = subscriptionsByEventType.get(eventClass); } if (subscriptions != null && !subscriptions.isEmpty()) { //將該事件的event和對(duì)應(yīng)的Subscription中的信息(包擴(kuò)訂閱者類和訂閱方法)傳遞給postingState for (Subscription subscription : subscriptions) { postingState.event = event; postingState.subscription = subscription; boolean aborted = false; try { //對(duì)事件進(jìn)行處理 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; }
同步取出該事件對(duì)應(yīng)的Subscription集合并遍歷該集合將事件event和對(duì)應(yīng)Subscription傳遞給postingState并調(diào)用postToSubscription方法對(duì)事件進(jìn)行處理,接下來(lái)看看postToSubscription方法:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case POSTING: invokeSubscriber(subscription, event); break; case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; case ASYNC: asyncPoster.enqueue(subscription, event); break; default: throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode); } }
取出訂閱方法的線程模式,之后根據(jù)線程模式來(lái)分別處理。舉個(gè)例子,如果線程模式是MAIN,提交事件的線程是主線程的話則通過(guò)反射,直接運(yùn)行訂閱的方法,如果不是主線程,我們需要mainThreadPoster將我們的訂閱事件入隊(duì)列,mainThreadPoster是HandlerPoster類型的繼承自Handler,通過(guò)Handler將訂閱方法切換到主線程執(zhí)行。
4.訂閱者取消注冊(cè)
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我們?cè)谟嗛喺咦?cè)的過(guò)程中講到過(guò)這個(gè)屬性,他根據(jù)訂閱者找到EventType,然后根據(jù)EventType和訂閱者來(lái)得到訂閱事件來(lái)對(duì)訂閱者進(jìn)行解綁。
5.核心架構(gòu)與利弊
核心架構(gòu)
從EventBus作者提供的圖我們可以看到EventBus的核心架構(gòu),其實(shí)就是基于觀察者模式來(lái)實(shí)現(xiàn)的,關(guān)于觀察者模式可以查看設(shè)計(jì)模式(五)觀察者模式這篇文章。
利與弊
EventBus好處比較明顯,它能夠解耦和,將業(yè)務(wù)和視圖分離,代碼實(shí)現(xiàn)比較容易。而且3.0后,我們可以通過(guò)apt預(yù)編譯找到訂閱者,避免了運(yùn)行期間的反射處理解析,大大提高了效率。當(dāng)然EventBus也會(huì)帶來(lái)一些隱患和弊端,如果濫用的話會(huì)導(dǎo)致邏輯的分散并造成維護(hù)起來(lái)的困難。另外大量采用EventBus代碼的可讀性也會(huì)變差。
參考資料
EventBus3.0源碼
EventBus3.0 源碼解析
EventBus 利弊與源碼解析
EventBus3.0源碼解讀
【Bugly干貨分享】老司機(jī)教你 “飆” EventBus 3
posted on 2016-10-27 23:46 安卓筆記俠 閱讀(556) 評(píng)論(0) 收藏 舉報(bào)


浙公網(wǎng)安備 33010602011771號(hào)