EventBus 3.1.1源碼分析

EventBus地址:https://github.com/greenrobot/EventBus

一、eventbus使用

EventBus是用于在Android和java中 發布/訂閱 的事件總線

模式圖

使用EventBus三部曲
1、定義事件Event

public static class MessageEvent { /* Additional fields if needed */ }

2、聲明并注解一個訂閱者

@Subscribe(threadMode = ThreadMode.MAIN)  
public void onMessageEvent(MessageEvent event) {/* Do something */};

其中@Subscribe(threadMode = ThreadMode.MAIN)的threadMode 可以指定此方法運行的線程模式,threadMode = ThreadMode.MAIN運行在UI線程,即onMessageEvent不能做耗時操作。

注冊和注銷訂閱者,如果你是在做android開發,那么應該在activity/fragment的生命周期中進行注冊/注銷。

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }

3、發布事件

EventBus.getDefault().post(new MessageEvent());

二、分析EventBus源碼

1、EventBus的注冊 EventBus.getDefault().register(this);

1-1、EventBus.getDefault()源碼

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

從源碼看,EventBus的getDefault()是采用的是單例模式,并且是線程安全,注意EventBus并不是一個嚴格意義上的單例模式,因為它的構造方法并不是私有的,所以你可以創建多個EventBus。
不了解單利模式可以看去之前寫的文章《設計模式—單例》
1-2、register(this);源碼

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

List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

先看這句List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);從命名可以看出是對訂閱者方法的查找,并返回訂閱者方法集合。再看下具體實現

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // 先從緩存中取出subscriberMethods,如果有則直接返回METHOD_CACHE的value
        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;
        }
    }
  • List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);檢查Map中是否緩存了此訂閱者的方法集合,有直接返回;
  • ignoreGeneratedIndex是個標志位,true的情況下是通過反射來獲取訂閱者方法列表,false下是在編譯期間生成SubscriberInfo,然后在運行時使用SubscriberInfo中保存的事件處理函數事件,減少了反射的耗時,會有運行速度上的提升,默認情況下ignoreGeneratedIndex值是false的
  • subscriberMethods = findUsingReflection(subscriberClass);看下源碼
    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass(); // 移至父類
        }
        return getMethodsAndRelease(findState);
    }

> FindState findState = prepareFindState();

    private static final int POOL_SIZE = 4;
    private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];

    private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
        return new FindState();
    }

這里使用了緩存來避免對象的頻繁創建所帶來的開銷,同時可以避免內存抖動;注意這里使用synchronized來避免出現兩個或兩個以上線程操作同一個FindState對象。[這個技巧可以用于出來摸個對象的頻繁創建銷毀,及內存抖動激烈的問題]
>> FindState

    static class FindState {
        // 訂閱者方法集合
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        // event為key,method為value
        final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        // 用method的名字生成一個method為key,用訂閱者類為value
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;
        Class<?> clazz;
        // 跳過父類,默認false-不跳過
        boolean skipSuperClasses;
        SubscriberInfo subscriberInfo;

        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

        // 釋放資源,并恢復默認設置
        void recycle() {
            subscriberMethods.clear();
            anyMethodByEventType.clear();
            subscriberClassByMethodKey.clear();
            methodKeyBuilder.setLength(0);
            subscriberClass = null;
            clazz = null;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

        ......

        // 移至父類【給clazz賦值父類】
        // 如果clazz是java包和android包里的,賦值null,并結束
        void moveToSuperclass() {
            if (skipSuperClasses) {
                clazz = null;
            } else {
                clazz = clazz.getSuperclass();
                String clazzName = clazz.getName();
                /** Skip system classes, this just degrades performance. */
                if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
                    clazz = null;
                }
            }
        }
    }

主要說明已經放到注釋上。

        // 將滿足條件的方法及參數類型添加到anyMethodByEventType中
        boolean checkAdd(Method method, Class<?> eventType) {
            // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
            // Usually a subscriber doesn't have methods listening to the same event type.
            // 這個涉及到兩層檢查
            // 第一層判斷有無method監聽此eventType,如果沒有則可直接把找到的method加到subscriberMethods中。
            // 第二層判斷是方法簽名,這里的方法簽名其實是methodName+eventType
            Object existing = anyMethodByEventType.put(eventType, method);
            if (existing == null) {
                return true;
            } else {
                if (existing instanceof Method) {
                    if (!checkAddWithMethodSignature((Method) existing, eventType)) {
                        // Paranoia check
                        throw new IllegalStateException();
                    }
                    // Put any non-Method object to "consume" the existing Method
                    anyMethodByEventType.put(eventType, this);
                }
                return checkAddWithMethodSignature(method, eventType);
            }
        }
    
        // 方法簽名
        private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
            // 拼接所謂的方法簽名
            methodKeyBuilder.setLength(0);
            methodKeyBuilder.append(method.getName());
            methodKeyBuilder.append('>').append(eventType.getName());
    
            String methodKey = methodKeyBuilder.toString();
            Class<?> methodClass = method.getDeclaringClass(); // 獲得聲明此method的類
            Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
            // “methodClassOld.isAssignableFrom(methodClass)” methodClassOld是否是methodClass的父類或者同一個類
            if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
                // Only add if not already found in a sub class
                return true;
            } else {
                // Revert the put, old class is further down the class hierarchy
                subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            }
        }
        

這兩個方法是FindState最重要的兩個方法,這里單獨舉例說明下:
第一種情況:比如一個類有多個訂閱方法,方法名不同,但它們的參數類型都是相同的(雖然一般不這樣寫,但不排除這樣的可能),那么遍歷這些方法的時候,會多次調用到checkAdd方法,由于existing不為null,那么會進而調用checkAddWithMethodSignature方法,但是由于每個方法的名字都不同,因此methodClassOld會一直為null,因此都會返回true。也就是說,允許一個類有多個參數相同的訂閱方法。
第二種情況:類B繼承自類A,而每個類都是有相同訂閱方法,換句話說,類B的訂閱方法繼承并重寫自類A,它們都有著一樣的方法簽名。方法的遍歷會從子類開始,即B類,在checkAddWithMethodSignature方法中,methodClassOld為null,那么B類的訂閱方法會被添加到列表中。接著,向上找到類A的訂閱方法,由于methodClassOld不為null而且顯然類B不是類A的父類,methodClassOld.isAssignableFrom(methodClass)也會返回false,那么會返回false。也就是說,子類繼承并重寫了父類的訂閱方法,那么只會把子類的訂閱方法添加到訂閱者列表,父類的方法會忽略。

>回到private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass),來看這個句findUsingReflectionInSingleClass(findState);

    private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            // This is faster than getMethods, especially when subscribers are fat classes like Activities
            // 獲取的是類【自身】聲明的所有方法,包含public、protected和private方法
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable th) {
            // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
            // 獲取的是類的所有共有方法,**這就包括自身的所有【public】方法,和從基類繼承的、從接口實現的所有public方法**
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }
        for (Method method : methods) {
            int modifiers = method.getModifiers(); // 獲取字段的修飾符
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                // 獲得一個方法參數數組(getparameterTypes用于返回一個描述參數類型的Class對象數組)
                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();
                // 不合法的注解方法 (必須為public,非static、非abstract)  
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

getDeclaredMethods()獲取的是類自身聲明的所有方法,包含public、protected和private方法。

getMethods()獲取的是類的所有共有方法,這就包括自身的所有public方法,和從基類繼承的、從接口實現的所有public方法。而使用此方法自然不需要再遍歷父類的方法,所以findState.skipSuperClasses = true;來跳過父類的遍歷。

int modifiers = method.getModifiers();獲取字段的修飾符
對應如下: PUBLIC: 1 PRIVATE: 2 PROTECTED: 4 STATIC: 8 FINAL: 16 SYNCHRONIZED: 32 VOLATILE: 64 TRANSIENT: 128 NATIVE: 256 INTERFACE: 512 ABSTRACT: 1024 STRICT: 2048

if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0)
private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;只獲取public類型的方法

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

當方法參數個數為1,并且此方法有Subscribe類型的注解時,通過findState.checkAdd(method, eventType)將方法和參數類型保存起來,如果保存成功,則構造一個SubscriberMethod對象把數據保存,并添加到findState.subscriberMethods集合中。

public class SubscriberMethod {
    final Method method; // 方法
    final ThreadMode threadMode; // 方法運行線程類型
    final Class<?> eventType; // 參數類型
    final int priority; // 優先級
    final boolean sticky; // 是否粘性
    /** Used for efficient comparison */
    String methodString; // 

    public SubscriberMethod(Method method, Class<?> eventType, ThreadMode threadMode, int priority, boolean sticky) {
        this.method = method;
        this.threadMode = threadMode;
        this.eventType = eventType;
        this.priority = priority;
        this.sticky = sticky;
    }

else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class))strictMethodVerification表示是否進行精細檢查,默認值是false。如果精細檢查【即strictMethodVerification=true】,并且method含有Subscribe對象的注解,則拋出異常

  • subscriberMethods = findUsingInfo(subscriberClass);總算分析完了findUsingReflection,我們接著分析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 {
                // 通過反射來查找訂閱方法
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);
    }
    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) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

> findState.subscriberInfo = getSubscriberInfo(findState);這里涉及到一個EventBus的高級用法,也就是通過注解在編譯期動態生成一個MyEventBusIndex.java類,從而避免通過反射來查找滿足條件的方法。下面給出官方文檔及兩篇這個高級用法的文章:

官方總文檔地址:http://greenrobot.org/eventbus/documentation/
官方地址:https://github.com/greenrobot/EventBus
博客一:EventBus高級使用姿勢
博客二:EventBus3.0新特性之Subscriber Index

如果沒有配置這個高級用法,findState.subscriberInfo值便會是null,然后通過反射去獲取方法并篩選。
MyEventBusIndex.java文件生成位置【我是用的是kotlin方案,不同的方案位置會有小的區別,但大致位置都是在source下】

MyEventBusIndex文件位置.png

注意在匿名類中是用EventBus時,這種高級用法是不會在MyEventBusIndex.java生成相關信息的(原因請自行百度),但會執行反射的邏輯來完成對方法的篩選。

subscribe(subscriber, subscriberMethod);

再來分析下register(this);最后一句代碼subscribe(subscriber, subscriberMethod);,源碼如下

    // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        // 從訂閱方法中拿到訂閱事件的類型  
        Class<?> eventType = subscriberMethod.eventType;
        // 創建一個新的訂閱
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        // 通過訂閱事件類型,找到所有的訂閱(Subscription),訂閱中包含了訂閱者,訂閱方法
        // CopyOnWriteArrayList是一個ArrayList的線程安全的變體,具體原理,使用請自行百度
        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) {
            // eventInheritance=true時(默認為true)
            // EventBus會考慮事件的超類,即事件如果繼承自超類,那么該超類也會作為事件發送給訂閱者。
            // 比如 A extends B implements C  發布者post(A),那么找訂閱者的時候不僅要找訂閱了事件A的訂閱者,還要找訂閱了B和C的訂閱者
            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();
                    // eventType是否是candidateEventType的父類或本身
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

> 大部分代碼的理解已放到代碼的注釋中了,這里我單獨拉出下面這段代碼分析下

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

先簡單寫一個列子,方法講解

public class ClazzA {
    public ClazzA() { EventBus.getDefault().register(this); }     

    @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
    public void eventbusMain(BaseEvent event) { }
}
public class BaseEvent { }
public class EventA extends BaseEvent { }

ClazzA構造的時候會執行EventBus的注冊流程,又因為ClazzA中的訂閱方法eventbusMainsticky所以會執行subscribe(subscriber, subscriberMethod);方法中的subscriberMethod.sticky模塊內代碼,而我們的EventBus是默認構造EventBus.getDefault(),也就是說eventInheritancetrue會執行eventInheritance代碼塊,如果這個時候stickyEvents.entrySet()中有兩個Event事件對象 【a是EventA類型,b是BaseEvent類型】,通過for循環后,這兩個對象都會交給eventbusMain(BaseEvent event)執行,也就是說eventType.isAssignableFrom(candidateEventType)這兩個對象都會通過,【第一次循環,BaseEvent是不是BaseEvent的父類或本身? 第二次循環,BaseEvent是不是ClazzA的父類或本身?------ 因為Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();是個集合,順序是不確定,可能是反的,不要糾結】

  • checkPostStickyEventToSubscription(newSubscription, 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, isMainThread());
        }
    }
    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 MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    // temporary: technically not correct as poster not decoupled from subscriber
                    invokeSubscriber(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);
        }
    }
    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);
        }
    }

ThreadMode 用法及說明

  • PostThread:默認的 ThreadMode,表示在執行 Post 操作的線程直接調用訂閱者的事件響應方法,不論該線程是否為主線程(UI 線程)。當該線程為主線程時,響應方法中不能有耗時操作,否則有卡主線程的風險。適用場景:對于是否在主線程執行無要求,但若 Post 線程為主線程,不能耗時的操作;
  • MainThread:在主線程中執行響應方法。如果發布線程就是主線程,則直接調用訂閱者的事件響應方法,否則通過主線程的 Handler 發送消息在主線程中處理——調用訂閱者的事件響應函數。顯然,MainThread類的方法也不能有耗時操作,以避免卡主線程。適用場景:必須在主線程執行的操作;
  • BackgroundThread:在后臺線程中執行響應方法。如果發布線程不是主線程,則直接調用訂閱者的事件響應函數,否則啟動唯一的后臺線程去處理。由于后臺線程是唯一的,當事件超過一個的時候,它們會被放在隊列中依次執行,因此該類響應方法雖然沒有PostThread類和MainThread類方法對性能敏感,但最好不要有重度耗時的操作或太頻繁的輕度耗時操作,以造成其他操作等待。適用場景:操作輕微耗時且不會過于頻繁,即一般的耗時操作都可以放在這里;
  • Async:不論發布線程是否為主線程,都使用一個空閑線程來處理。和BackgroundThread不同的是,Async類的所有線程是相互獨立的,因此不會出現卡線程的問題。適用場景:長耗時操作,例如網絡訪問。

mainThreadPoster.enqueue(subscription, event);主線程執行訂閱方法。

private final Poster mainThreadPoster;

EventBus(EventBusBuilder builder) {
    ......
    mainThreadSupport = builder.getMainThreadSupport();
    mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
    ......
}
    MainThreadSupport getMainThreadSupport() {
        if (mainThreadSupport != null) {
            return mainThreadSupport;
        } else if (Logger.AndroidLogger.isAndroidLogAvailable()) {
            // android的Ui線程
            Object looperOrNull = getAndroidMainLooperOrNull();
            return looperOrNull == null ? null :
                    new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
        } else {
            return null;
        }
    }

其中Logger.AndroidLogger.isAndroidLogAvailable()其實是通過反射android中的"android.util.Log"包是否存在來實現的,代碼如下:

public interface Logger {

    ........
    public static class AndroidLogger implements Logger {
        static final boolean ANDROID_LOG_AVAILABLE;

        static {
            boolean android = false;
            try {
                android = Class.forName("android.util.Log") != null;
            } catch (ClassNotFoundException e) {
                // OK
            }
            ANDROID_LOG_AVAILABLE = android;
        }

        public static boolean isAndroidLogAvailable() {
            return ANDROID_LOG_AVAILABLE;
        }
       ........
    }
    .......
}

在靜態代碼塊中做的反射【只會執行一次】,靜態代碼塊的知識偏離本文重點,請自行百度。

    Object getAndroidMainLooperOrNull() {
        try {
            // 獲得android主線程的looper
            return Looper.getMainLooper();
        } catch (RuntimeException e) {
            // Not really a functional Android (e.g. "Stub!" maven dependencies)
            return null;
        }
    }

這個方法是用來獲得android主線程的looper對象。

public interface MainThreadSupport {
    boolean isMainThread();
    Poster createPoster(EventBus eventBus);

    class AndroidHandlerMainThreadSupport implements MainThreadSupport {
        private final Looper looper;
        public AndroidHandlerMainThreadSupport(Looper looper) {
            this.looper = looper;
        }
        @Override
        public boolean isMainThread() {
            return looper == Looper.myLooper();
        }
        @Override
        public Poster createPoster(EventBus eventBus) {
            return new HandlerPoster(eventBus, looper, 10);
        }
    }
}
public class HandlerPoster extends Handler implements Poster {
    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        // 構造一個post意圖對象
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            // 將構造的PendingPost 加入到隊列中
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                // handler標記為活躍狀態
                handlerActive = true;
                // 發送PendingPost對象
                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                // 從隊列中獲得要執行的PendingPost 
                PendingPost pendingPost = queue.poll();
                // 雙重加鎖檢查,如果隊列中沒有信息,則hanlder狀態標記為不活躍狀態,同事退出循環
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                // 執行訂閱者的訂閱方法
                eventBus.invokeSubscriber(pendingPost);
                // 循環發送隊列中的所有pendingPost對象
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

可以看出MainThreadSupport是通過主線程的Looper構造一個主線程的handler對象,這個handler中維護了一個隊列PendingPostQueue,也就是說mainThreadPoster.enqueue(subscription, event);是通過構造PendingPost對象并添加到隊列中,然后激活隊列來實現發送。

backgroundPoster.enqueue(subscription, event);后臺線程中執行響應方法

final class BackgroundPoster implements Runnable, Poster {
    private final PendingPostQueue queue;
    private final EventBus eventBus;
    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }
    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!executorRunning) {
                executorRunning = true;
                eventBus.getExecutorService().execute(this);
            }
        }
    }
    @Override
    public void run() {
        try {
            try {
                while (true) {
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }
}
// 創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。 
private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();

主要代碼就一句eventBus.getExecutorService().execute(this);交給線程池處理。

asyncPoster.enqueue(subscription, event);不論發布線程是否為主線程,都使用一個空閑線程來處理。和BackgroundThread不同的是,Async類的所有線程是相互獨立的,因此不會出現卡線程的問題。

class AsyncPoster implements Runnable, Poster {
    private final PendingPostQueue queue;
    private final EventBus eventBus;
    AsyncPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        queue = new PendingPostQueue();
    }
    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        queue.enqueue(pendingPost);
        eventBus.getExecutorService().execute(this);
    }
    @Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }
}

AsyncPosterBackgroundPoster代碼基本一樣,這里就不分析。它們兩個主要區別就是BackgroundPoster把一堆訂閱方法放在一個線程中執行,而AsyncPoster是為每一個訂閱方法都創建一個線程來單獨執行。

  • 總結:到這終于分析完了EventBus的register()的整個流程。下面我繪制了一個流程圖來方便理解整個注冊流程。
    EventBus整個register流程

2、EventBus的訂閱方法聲明

@Subscribe(threadMode = ThreadMode.MAIN)  
public void onMessageEvent(MessageEvent event) {/* Do something */};

2-1、訂閱方法說明
在上面的EventBus.getDefault()流程分支中,我們得知EventBus的訂閱方法必須是public,一個參數,并且要一定要有@Subscribe的注解,才能成功的將該方法添加到EventBus的訂閱方法列表中,同時EventBus提供了兩種方法來查找我們的訂閱方法,一種是反射【效率低】,另一種是通過注解,在編譯期動態生成訂閱者方法列表【效率高】。
2-2、Subscribe都有哪些注解參數

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;
    /**
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false;
    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different {@link ThreadMode}s! */
    int priority() default 0;
}

源碼中看出就三個屬性參數,分別是線程模式、是否粘性、優先級。

3、EventBus發布事件EventBus.getDefault().post(new MessageEvent());

3-1、void post(Object event)

    public void post(Object event) {
        // 獲得當前線程的PostingThreadState封裝對象
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);
        
        if (!postingState.isPosting) {  // 為發送狀態
            postingState.isMainThread = isMainThread(); // 是否主線程
            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;
            }
        }
    }

第一行源碼是從currentPostingThreadState中獲取PostingThreadState對象,來下看currentPostingThreadState的定義

    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

看來currentPostingThreadState是一個ThreadLocal<T>對象,ThreadLocal是一個線程內部的數據存儲類,通過它可以在指定的線程中存儲數據,而這段數據是不會與其他線程共享的。【下面是一段跑題代碼】

public class ThreadLocal<T> {
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
}
// 其內部原理是通過生成一個它包裹的泛型對象的數組,在不同的線程會有不同的數組索引值,
// 通過這樣就可以做到每個線程通過 get() 方法獲取的時候,取到的只能是自己線程所對應的數據。 

回到正題繼續分析

    /** For ThreadLocal, much faster to set (and get multiple values). */
    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<>();    // 事件隊列
        boolean isPosting;    // 是否在執行postSingleEvent()方法
        boolean isMainThread;  // 是否是UI線程
        Subscription subscription;
        Object event;
        boolean canceled;
    }

PostingThreadState主要是封裝了一些post時的參數。

post(Object event)的核心代碼就是這個句,postSingleEvent(eventQueue.remove(0), postingState);

   private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            // 獲取到eventClass所有父類的集合
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                // 有一個為true,即真個運算結果為true
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            // 沒有找到此事件類型的訂閱者邏輯
            if (logNoSubscriberMessages) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            // sendNoSubscriberEvent=true發送沒有此事件類型的訂閱者的事件
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);是用來獲取eventClass所繼承的父類,及所有接口。

    /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
    private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
        synchronized (eventTypesCache) {
            // eventTypesCache一個map的緩存對象,通過緩存,提高運行效率
            List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
            if (eventTypes == null) {
                eventTypes = new ArrayList<>();
                Class<?> clazz = eventClass;
                while (clazz != null) {
                    eventTypes.add(clazz);
                    addInterfaces(eventTypes, clazz.getInterfaces());
                    clazz = clazz.getSuperclass();
                }
                eventTypesCache.put(eventClass, eventTypes);
            }
            return eventTypes;
        }
    }
    /** Recurses through super interfaces. */
    //   遞歸方式查找出所有接口
    static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
        for (Class<?> interfaceClass : interfaces) {
            if (!eventTypes.contains(interfaceClass)) {
                eventTypes.add(interfaceClass);
                addInterfaces(eventTypes, interfaceClass.getInterfaces());
            }
        }
    }

這里通過遞歸來查找出所有的接口,并添加到eventTypes中;

    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            // 所有訂閱了eventClass的事件集合
            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;
    }

postToSubscription(subscription, event, postingState.isMainThread);上面register()中已有相關分析,這里不贅述了;

3-2、void postSticky(Object event)

    private final Map<Class<?>, Object> stickyEvents;

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

如果是粘性事件,將此事件添加到stickyEvents中,然后調用void post(Object event),就和上面的分析一樣了,這里把event添加到stickyEvents目的是,當后續有register(this);時執行sticky訂閱方法。

4、EventBus的反注冊 EventBus.getDefault().unregister(this);

1-1、unregister(this)源碼

    /** 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 {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
    /** 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--;
                }
            }
        }
    }

unregister就是進行一些數據從集合中移除,資源回收的操作和重置,看看就可以了。

PS:終于算分析完了,一貫只看不寫我的,第一次寫這么長的源碼分析文章,寫到最后自己都想放棄,但抱著做事要有始有終,還是堅持寫完了@@@@@@~~~~~!!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

推薦閱讀更多精彩內容

  • 我每周會寫一篇源代碼分析的文章,以后也可能會有其他主題.如果你喜歡我寫的文章的話,歡迎關注我的新浪微博@達達達達s...
    SkyKai閱讀 24,979評論 23 184
  • 原文鏈接:http://blog.csdn.net/u012810020/article/details/7005...
    tinyjoy閱讀 563評論 1 5
  • 對于Android開發老司機來說肯定不會陌生,它是一個基于觀察者模式的事件發布/訂閱框架,開發者可以通過極少的代碼...
    飛揚小米閱讀 1,485評論 0 50
  • 最近在項目中使用了EventBus(3.0),覺得非常好用,于是就看了一些關于EventBus源碼分析的文章,現在...
    shenhuniurou閱讀 1,522評論 0 4
  • 大腦思考時,同時發出一段聲接收一段音匹配一個概念,由此發現概念的聲音形態。這一刻,對稱邏輯呈現,哲學隨之誕生。
    JUNJKD閱讀 161評論 0 0