EventBus 源碼解讀

EventBus 基礎
發佈者通過EventBus發佈事件,訂閱者通過EventBus訂閱事件。當發佈者發佈事件時,訂閱該事件的訂閱者的事件處理方法將被調用。這裏的事件,指的是一個對象類型。只有對象類型相同時,訂閱方法纔會被處理,還支持訂閱方法在不同的線程中被調用

首先是註冊方法,獲取對象的Class對象,然後去SubscriberMethodFinder類中查找,

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized(this) {
        Iterator var5 = subscriberMethods.iterator();

        while(var5.hasNext()) {
            SubscriberMethod subscriberMethod = (SubscriberMethod)var5.next();
            this.subscribe(subscriber, subscriberMethod);
        }

    }
}

SubscriberMethodFinder findSubscriberMethods方法,首先去METHOD_CACHE緩存中查找是否對應的List集合,METHOD_CACHE是個Map集合,每個Class對應的List 都緩存在這個集合中,由於我們是第一次調用,這個獲取的肯定是個null,ignoreGeneratedIndex這個我們也沒賦值過,所以是個false,因此走findUsingInfo方法

findSubscriberMethods

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    List<SubscriberMethod> subscriberMethods = (List)METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    } else {
        if (this.ignoreGeneratedIndex) {
            subscriberMethods = this.findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = this.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;
        }
    }
}

findUsingInfo方法
傳入的是我們的對象的Class對象,首先初始化了一個FindState類,然後根據當前類對象,查找是否有@Subscribe 註解的類,並且依次遍歷父Class對象,直到父類是系統爲止

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != 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 {
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}

moveToSuperclass方法,獲取父類類對象,如果是系統的則直接返回null,當然如果設置了skipSuperClasses爲true,則也不會搜索父類

void moveToSuperclass() {
        if (this.skipSuperClasses) {
            this.clazz = null;
        } else {
            this.clazz = this.clazz.getSuperclass();
            String clazzName = this.clazz.getName();
            if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
                this.clazz = null;
            }
        }

    }

findUsingReflectionInSingleClass方法,首先獲取類所有的方法,然後一一查找方法上面的註解,如果找到了Subscribe註解,則把註解的ThredMode數據和方法,參數類型等數據封裝成一個SubscriberMethod對象,存在findState.subscriberMethods集合中,並且參數只能有一個,如果有多個,並且設置了strictMethodVerification爲true的話,則拋出一個異常。

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);
                //找到註解爲Subscribe方法
                if (subscribeAnnotation != null) {
                    Class<?> eventType = parameterTypes[0];
                    if (findState.checkAdd(method, eventType)) {
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        //把方法和參數類型相關參數封裝成一個SubscriberMethod對象存在findState.subscriberMethods集合中
                        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");
        }
    }
}

前面我們知道找到的註解的方法都封裝在findState.subscriberMethods集合中,執行getMethodsAndRelease方法則是把findState.subscriberMethods集合中的數據返回回去,

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != 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 {
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
}

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
    List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
    findState.recycle();
    synchronized (FIND_STATE_POOL) {
        for (int i = 0; i < POOL_SIZE; i++) {
            if (FIND_STATE_POOL[i] == null) {
                FIND_STATE_POOL[i] = findState;
                break;
            }
        }
    }
    return subscriberMethods;
}

在回到findSubscriberMethods方法,獲取到所有方法後,緩存到METHOD_CACHE集合中,並且將所有方法返回

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    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;
    }
}

回到Event的register方法

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

後又調用了subscribe方法,傳入的參數就是我們註冊的對象,和註冊對象裏的訂閱方法,把我們註冊的對象和方法封裝成一個Subscription對象,根據方法參數類型,從subscriptionsByEventType集合中獲取是否有CopyOnWriteArrayList集合
如果這種事件類型還沒註冊個過,則重新生成一個集合,並把當前的subsriptions對象添加集合中,而Subscription對象後面又添加到Subscription對象集合當中。這個subscriptionsByEventType就存儲了所有事件類型,和事件類型對應的要接收所有對象。
後面post方法的時候就是從這個集合中獲取對應的執行類和方法再反射執行的

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        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++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);

    if (subscriberMethod.sticky) {
        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();
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
}

小結:register傳入的參數是我們訂閱者對象,然後查找所有該對象類裏面所有帶有註解Subscribe的方法,並且該方法有且只有一個參數,訂閱者纔會收到事件,然後把該對象和對應的參數類型封裝成Subscription對象存在subscriptionsByEventType Map集合中,該集合的key類型爲參數類型。

當我準備設置strictMethodVerification變量時,通過EventBus.builder().strictMethodVerification(true)設置,但是註冊還是通過EventBus.getDefault().register()。發現設置的根本無效.
查看代碼得知build返回的是直接new 出來的一個EventBus,而getDefault則是全局唯一,單例的,並且裏面這個值默認是個false.現在發現如果要重新設置這個值,則就得重新生成一個EventBus對象,當然,其他的屬性值也是如此。爲什麼這麼設計呢,如果不這樣設計,那隻要一個地方改變了這個值,則所有地方都會影響。

public EventBus build() {
    return new EventBus(this);
}

public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

看使用,post方法

public void post(Object event) {
    PostingThreadState postingState = currentPostingThreadState.get();
    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 {
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

調用了postSingleEvent方法,因爲我們沒有設置eventInheritance屬性,則走下面postSingleEventForEventType,方法,如果設置了這個屬性,則所有訂閱了該事件,事件實現的接口,事件的父類以及父類實現的接口的方法都會執行。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;

    if (eventInheritance) {
        1 查找所有事件類型,包含事件父類已經父類實現的接口
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            2 執行訂閱者的方法
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
        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));
        }
    }
}

postSingleEventForEventType方法,從subscriptionsByEventType獲取所有訂閱了該事件類型的調用者,然後根據是否在主線程還是其他線程一一對其調用,調用了postToSubscription方法

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        for (Subscription subscription : subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
                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;
}

根據當前調用者的線程情況,再結合註解上面的threadMode屬性判斷是否在哪個線程執行,

ThreadMode.POSTING 訂閱者方法將在發佈事件所在的線程中被調用。這是 默認的線程模式。事件的傳遞是同步的,一旦發佈事件,所有該模式的訂閱者方法都將被調用。這種線程模式意味着最少的性能開銷,因爲它避免了線程的切換。因此,對於不要求是主線程並且耗時很短的簡單任務推薦使用該模式。使用該模式的訂閱者方法應該快速返回,以避免阻塞發佈事件的線程,這可能是主線程
ThreadMode.MAIN 訂閱者方法將在主線程(UI線程)中被調用。因此,可以在該模式的訂閱者方法中直接更新UI界面。如果發佈事件的線程是主線程,那麼該模式的訂閱者方法將被直接調用。使用該模式的訂閱者方法必須快速返回,以避免阻塞主線程。
ThreadMode.MAIN_ORDERED 訂閱者方法將在主線程(UI線程)中被調用。因此,可以在該模式的訂閱者方法中直接更新UI界面。事件將先進入隊列然後才發送給訂閱者,所以發佈事件的調用將立即返回。這使得事件的處理保持嚴格的串行順序。使用該模式的訂閱者方法必須快速返回,以避免阻塞主線程。
ThreadMode.BACKGROUND 訂閱者方法將在後臺線程中被調用。如果發佈事件的線程不是主線程,那麼訂閱者方法將直接在該線程中被調用。如果發佈事件的線程是主線程,那麼將使用一個單獨的後臺線程,該線程將按順序發送所有的事件。使用該模式的訂閱者方法應該快速返回,以避免阻塞後臺線程。
ThreadMode.ASYNC 訂閱者方法將在一個單獨的線程中被調用。因此,發佈事件的調用將立即返回。如果訂閱者方法的執行需要一些時間,例如網絡訪問,那麼就應該使用該模式。避免觸發大量的長時間運行的訂閱者方法,以限制併發線程的數量。EventBus使用了一個線程池來有效地重用已經完成調用訂閱者方法的線程。

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);
    }
}

其中POSTING執行的方法,反射的調用其對應的方法

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);
    }
}

如果當前post的代碼沒有在主線程中,則利用主線程的mainThreadPoster 切換到主線程中執行

register是把對象存起來,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());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章