EventBus要點記錄

1、EventBus方法註冊
先從註冊的對象中找到對應的方法
1)先從對外聲明的方法找,如果發生異常,再找全部方法
找全部方法的時候會設置變量findState.skipSuperClasses = true; 這樣就不用再次找父類的方法了

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
    try {
        methods = findState.clazz.getMethods();

2)方法必須是public修飾的,並且不能是抽象 靜態的方法(可設置讓其報出異常)
3)方法必須是Subscribe註解修飾,並且方法的參數必須是有且只有1個(可設置讓其報出異常)
4)找完本類後,通常回去找對應的父類的方法,(java和android這樣的父類不包括)
5)負責查找方法的類是FindState,這個用到了享元模式,方便對象的複用,每次用完會把對象的狀態置爲原值,並放入緩存池中
6)如果是粘性方法,會取出對應的粘性事件,發給註冊的這個方法

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
        try {
            methods = findState.clazz.getMethods();
        } catch (LinkageError error) { // super class of NoClassDefFoundError to be a bit more broad...
            String msg = "Could not inspect methods of " + findState.clazz.getName();
            if (ignoreGeneratedIndex) {
                msg += ". Please consider using EventBus annotation processor to avoid reflection.";
            } else {
                msg += ". Please make this class visible to EventBus annotation processor to avoid reflection.";
            }
            throw new EventBusException(msg, error);
        }
        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");
        }
    }
}

二、發送事件
發送消息分爲發送正常事件和發送粘性事件:
發送粘性事件和發送正常事件的區別在於,把粘性事件放到粘性集合中放一份,然後調用發送正常事件的方法

    1、 public void post(Object event)
    2、 public void postSticky(Object event) {
    synchronized (stickyEvents) {
        stickyEvents.put(event.getClass(), event);
    }
    // Should be posted after it is putted, in case the subscriber wants to remove immediately
    post(event);
}

發送事件分爲以下幾步:
1、把發送的事件放入待發送的集合中
2、找到這個事件的所有父類和實現的接口(允許事件繼承關係的話,可通過變量設置)
3、遍歷第2步中找到的所有事件,根據事件找到對應的方法,進行執行
根據事件找方法的操作爲從map集合中找,key爲這個事件的類型,value爲存放了所有監聽這個事件的方法的集合
4、方法執行中,涉及到在哪個線程執行的問題
EvenBus中方法所在的線程分爲五種:
1)POSTING 方法執行線程和發事件的線程在同一個線程,這樣可能會引起阻塞,必須等一個方法執行完後,才能把事件傳遞個下一個方法
2)MAIN 方法在主線程執行,如果發送事件的線程也在主線程,也可能會造成阻塞,需要等方法執行完後,纔會傳遞給下一個方法
3)MAIN_ORDERED 方法在主線程執行,不會對發送事件造成阻塞,會把監聽該事件的方法放到handler的消息隊列中執行
4)BACKGROUND 子線程中執行,如果發送事件的線程不是主線程,則直接會在這個線程中執行,這種情況同樣可能會引起阻塞,必須等一個方法執行完後,才能把事件傳遞個下一個方法
5)ASYNC 子線程中執行,總是保持和發送事件的線程不在同一個線程,會通過線程池進行執行方法

三、取消註冊事件
這一步比較簡單,eventBus裏面有一個map集合,key爲對應的註冊的對象類,value爲list集合,裏面保存着和這對象類有關的所有event事件類型。
1、根據這個對象找出所有的事件類型,
2、然後再根據事件類型從另一個集合中找出事件類型所對應的所有方法
3、遍歷這些方法,移除掉屬於這個對象類的方法
取消註冊事件就算成功了

在註冊時,會根據是否用到了註冊索引類來進行註冊,這個是在編譯階段就把對應的方法找到了,可以提高執行效率,以後再進行分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章