記得第一次寫EventBus還是在一年前,轉眼間又是一年了,發現對于EventBus的原始碼細節有點模糊,挖個坑捋捋EventBus的原始碼
由于專案中使用且當前最新版本原始碼變化不大,本文貼出的原始碼基于EventBus3.0.0,關于EventBus的用法可以移步我之前的文章:
Android EventBus你需要了解的都在這
EventBus.register
首先,EventBus的原理是基于發布訂閱模式,有些萌新開始會以為是觀察者模式,其實它跟觀察者模式的區別在于不需要觀察者(訂閱者)和目標(發布者)直接互動,而是通過調度中心來進行分發事件,實作了它們之間的解耦,
看原始碼首先可以從我們使用的第一步,注冊訂閱事件的方法register開始:
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
其中
SubscriberMethodFinder是EventBus用來管理訂閱事件的方法類SubscriberMethod是EventBus的訂閱方法(使用@Subscribe注解的方法),其中封裝了訂閱者的回呼方法、執行緒模式、EventClass、是否為粘性事件等資訊
EventBus通過傳入的Object物件subscriber的class,構造出了一個SubscriberMethod陣列,看看構造陣列的findSubscriberMethods方法中有什么
SubscriberMethodFinder.findSubscriberMethods
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
//如果快取里有的話直接使用
if (subscriberMethods != null) {
return subscriberMethods;
}
//針對是否忽略繼承的索引,采用不同的查找策略
//通過反射獲取Subscriber注解的方法list,這塊就不往下跟了,各位有興趣可以自己看看
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 {
//如果構造出的subscriberMethods不為空,則放入快取
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
簡單說,findSubscriberMethods方法中主要是通過反射獲取目標類中添加了@Subscriber注解的方法陣列
然后register()中會遍歷方法陣列,呼叫subscribe方法訂閱:
EventBus.subscribe
其中
Subscription是包裹訂閱類和訂閱者資訊的包裝類SubscriberMethod是上邊說過的EventBus的訂閱方法,其中封裝了訂閱者的回呼方法、執行緒模式、EventClass、是否為粘性事件等資訊,為了防止各位弄混,再強調一下typesBySubscriber是EventBus中存放的“訂閱者-事件型別”串列
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//獲取事件型別(EventClass)對應的訂閱(訂閱者,訂閱者方法)list
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
//指定的事件型別沒有對應的觀察物件的時候,初始化list再添加進去
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//如果同一個類重復訂閱同一個事件,拋出EventBusException例外
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
//遍歷subscriptions,依據優先級,將新的訂閱插入到list中
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
// 從“訂閱者-事件型別”串列中嘗試獲取該訂閱者對應的所有事件型別
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
//如果是訂閱者的第一個訂閱事件,構造一個typesBySubscriber put之后再添加
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//如果這個事件是黏性事件
if (subscriberMethod.sticky) {
//是否判斷同型別的超類flag
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();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
// post黏性事件 checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
// post黏性事件 checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
對于普通事件,添加到subscribedEvents后該時間就處理完畢了,低于黏性事件,則還會使用checkPostStickyEventToSubscription(newSubscription, stickyEvent);方法繼續向該觀察者通知所有的黏性事件
//跳過stickyEvent為空的情況
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here.
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}
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);
}
}
這里就是post處理事件的邏輯了,
到這里本篇EventBus.register注冊方法的決議就結束了,詳細的代碼決議會放到后續的處理post事件決議
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/382032.html
標籤:其他
