解析EventBus3.0源碼

EventBus

介紹

EventBus是Android和Java的一個發(fā)布和訂閱事件總線第三方庫。

官網(wǎng)

Features(特點):

  1. 簡化組件間通信
    1. 分離事件發(fā)送者和接收者
    2. 能夠很好的在Activity姑躲,F(xiàn)ragment和后臺線程之間協(xié)作
    3. 避免復(fù)雜和容易出錯的依賴關(guān)系和生命周期問題
  2. 代碼簡潔
  3. 反應(yīng)迅速
  4. 體積斜豕ァ(60k jar)
  5. 被大量的app實踐使用過
  6. 具有發(fā)送線程臀玄,訂閱優(yōu)先級等特性
使用示例
  1. 創(chuàng)建要傳遞的事件實體

    public static class MessageEvent { 
        /* Additional fields if needed */
    }
    
  1. 訂閱者:聲明和注釋訂閱方法,指定一個線程模式(MAIN, POSTING, MAIN_ORDERED, BACKGROUND, ASYNC)

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

    訂閱者進行注冊及取消注冊。例如在Android上害碾,Activity和Fragment通常應(yīng)該根據(jù)它們的生命周期進行注冊

    @Override
     public void onStart() {
         super.onStart();
         EventBus.getDefault().register(this);
     }
    
     @Override
     public void onStop() {
         super.onStop();
         EventBus.getDefault().unregister(this);
     }
    
  1. 發(fā)布事件

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

EventBus是基于觀察者模式擴展而來的瘩例,不了解觀察者模式的可以先提前了解啊胶,再來閱讀這個解析文章。

EventBus.getDefault().register(this)

首先從注冊訂閱者開始分析

    /** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        EventBus instance = defaultInstance;
        if (instance == null) {
            synchronized (EventBus.class) {
                instance = EventBus.defaultInstance;
                if (instance == null) {
                    instance = EventBus.defaultInstance = new EventBus();// 分析點1
                }
            }
        }
        return instance;
    }

在getDefault()中使用雙重校驗加鎖的單例模式創(chuàng)建EventBus實例

接著看下分析點1處的EventBus的構(gòu)造方法實現(xiàn)

    public EventBus() {
        this(DEFAULT_BUILDER);// 分析點2
    }

    EventBus(EventBusBuilder builder) {
        logger = builder.getLogger();
        subscriptionsByEventType = new HashMap<>();// 分析點3
        typesBySubscriber = new HashMap<>();// 分析點4
        stickyEvents = new ConcurrentHashMap<>();// 分析點5
        mainThreadSupport = builder.getMainThreadSupport();// 分析點6
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
        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);// 分析點7
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;// 分析點8
    }

在構(gòu)造方法的分析點2中可以看出,它調(diào)用了另一個有參構(gòu)造方法,其中的參數(shù)是一個類型為 EventBuilder 的 DEFAULT_BUILDER 對象,這里明顯構(gòu)建者模式, DEFAULT_BUILDER 對象中包括了許多 EventBus 的默認(rèn)設(shè)置.猜測可以通過 EventBuilder 類型來構(gòu)建自定義的EventBus對象.繼續(xù)分析 DEFAULT_BUILDER 可知

public class EventBusBuilder {
    ...
    EventBusBuilder() {
        // DEFAULT_BUILDER沒有進行什么特殊的處理,僅僅是實例自身
    }
    ...
}

回到EventBus的有參構(gòu)造方法,分析點3 定義為private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;是一個key為Class,value為Subscription的線性表.而Subscription是什么呢垛贤?

/**
 Subscription是一個訂閱信息對象,有兩個字段: Object(用于保存訂閱者,即EventBus.getDefault().register(this)中的this對象), SubscriberMethod (用于保存訂閱方法,即被@Subcribe注解的方法)
**/
final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    /**
     * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
     * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
     */
    volatile boolean active;

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Subscription) {
            Subscription otherSubscription = (Subscription) other;
            return subscriber == otherSubscription.subscriber
                    && subscriberMethod.equals(otherSubscription.subscriberMethod);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
    }
}


/**
SubscriberMethod 可以看到它的字段包括 Method 方法本身, ThreadMode 訂閱方法的執(zhí)行線程, eventType 訂閱方法的參數(shù)的類型, priority 優(yōu)先級, sticky 是否是黏性事件焰坪。
**/
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;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else if (other instanceof SubscriberMethod) {
            checkMethodString();
            SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
            otherSubscriberMethod.checkMethodString();
            // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
            return methodString.equals(otherSubscriberMethod.methodString);
        } else {
            return false;
        }
    }

    private synchronized void checkMethodString() {
        if (methodString == null) {
            // Method.toString has more overhead, just take relevant parts of the method
            StringBuilder builder = new StringBuilder(64);
            builder.append(method.getDeclaringClass().getName());
            builder.append('#').append(method.getName());
            builder.append('(').append(eventType.getName());
            methodString = builder.toString();
        }
    }

    @Override
    public int hashCode() {
        return method.hashCode();
    }
}

接著看分析點4定義為private final Map<Object, List<Class<?>>> typesBySubscriber;是一個key為 Object , value為Class的集合.

分析點5定義為private final Map<Class<?>, Object> stickyEvents是一個用于黏性事件處理的字段。

分析點6新建了三個不同類型的事件發(fā)送器:

  1. mainThreadPoster:實際是 HandlerPoster 類型的實例對象, HandlerPoster 繼承Handler, Looper是 Looper.getMainLooper ,這里通過Handler機制在主線程中回調(diào)訂閱方法
  2. backgroundPoster:實際是實現(xiàn)了 Runnable 接口的對象,將方法加入后臺隊列中,最后通過線程池去執(zhí)行,由于添加了synchronized關(guān)鍵字并使用了 executorRunning 這個boolean類型的字段進行控制,線程池保證了同一時間只有一個任務(wù)會被線程池執(zhí)行
  3. asyncPoster:實際是實現(xiàn)了 Runnable 接口的對象,與backgroundPoster類似,區(qū)別在于沒有字段和synchronized關(guān)鍵字的控制,同一時間可以有多個任務(wù)被線程池執(zhí)行
/**
mainThreadPoster
**/
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);// 此處的Looper為Looper.getMainLooper()
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                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 = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                eventBus.invokeSubscriber(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;
        }
    }
}


/**
backgroundPoster
**/
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;
        }
    }

}


/**
asyncPoster
**/
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);
    }

}

接著分析點7新建了 SubscriberMethodFinder 對象,根據(jù)命名可以知道這是一個查找訂閱對象中的訂閱方法的類,這個文章的后面會分析

分析點8是一個線程池聘惦,它是在 DEFAULT_BUILDER 實例自身的時候某饰,通過Executor的newCachedThreadPool()方法創(chuàng)建,它是一個有則用善绎、無則創(chuàng)建黔漂、無數(shù)量上限的線程池。也就是上面backgroundPoster,asyncPoster會用到的線程池.

上面是EventBus的getDefault()方法接下來終于可以分析register(this)的邏輯

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

需要關(guān)注的地方有兩個,分析點9處根據(jù)代碼上下文和方法名可以知道是找出訂閱類中的所有訂閱方法并得到一個訂閱方法的List.而分析點10顯然是遍歷這個列表再進行操作.這里先追蹤分析點9

    private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();// 一個以class為key,List<SubscriberMethod>為value的hashmap
    ...
    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // 先從hashmap取,沒有則證明該Class沒有訂閱過
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        // ignoreGeneratedIndex這個字段是用來判斷是否使用APT生成代碼優(yōu)化尋找訂閱方法的過程,默認(rèn)為false
        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            // 所以一般調(diào)用的是 findUsingInfo 這個方法
            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;
        }
    }

    
    
    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        /* prepareFindState()是獲取一個FindState實例,不繼續(xù)跟蹤改變該方法禀酱。而FindState是 SubscriberMethodFinder 的內(nèi)部類炬守,這個方法主要做一個初始化、回收對象等工作剂跟。*/
        FindState findState = prepareFindState();
        // initForSubscriber(Class clazz)將訂閱對象的Class用于初始化FindState
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            // 首次初始化時,subscriberInfo 為null,所以此處獲得的是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 {
                // 最終調(diào)用該方法獲取訂閱方法集合
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        // 分析點9.1
        return getMethodsAndRelease(findState);
    }

    // SubscriberMethodFinder的內(nèi)部類
    static class FindState {
        final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
        final Map<Class, Object> anyMethodByEventType = new HashMap<>();
        final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;
        Class<?> clazz;
        boolean skipSuperClasses;
        SubscriberInfo subscriberInfo;

        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            // 這里可以知道初始化時subscriberInfo為null值
            subscriberInfo = null;
        }
        
        ...
    }

    
    // 重點方法
    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) {
                    // 重點1
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    if (subscribeAnnotation != null) {
                        // 重點2
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            // 重點3
                            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");
            }
        }
    }

看上面的代碼注釋可知重點在于findUsingReflectionInSingleClass這個方法减途,它做了什么呢

  1. 通過反射獲取了訂閱對象的類的所有聲明方法(有點繞口)
  2. 遍歷所有聲明方法獲得以@Subscribe作為注解的方法
  3. 檢查上面獲得的方法的入?yún)⑹遣皇侵挥幸粋€
  4. checkadd根據(jù)方法和方法的入?yún)z查是否已經(jīng)記錄過同類型入?yún)⒌挠嗛喎椒?/li>
  5. 如果滿足上面的條件則新建一個SubscriberMethod 對象加入到findState.subscriberMethods這個集合中

這時候分析回到findUsingInfo方法中,它會通過 findState.moveToSuperclass(); 繼續(xù)去檢查父類的class,當(dāng)然這個循環(huán)會終結(jié)在系統(tǒng)的class,也就是不檢查系統(tǒng)的class.最后我們要看的就是分析點9.1getMethodsAndRelease(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;
    }

很簡單,構(gòu)建了一個新的List<SubscriberMethod>進行返回,回收findState對象.關(guān)于FindState對象的緩存池處理不是重點.所以跳過分析.

終于回到了分析點9處獲得了一個關(guān)于訂閱對象的訂閱方法集合List<SubscriberMethod>,接著就是分析點10的遍歷集合中的subscribe(subscriber, subscriberMethod);方法.

    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;
        // 構(gòu)建一個Subscription對象,該對象持有訂閱對象以及訂閱集合的引用
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        /* 從subscriptionsByEventType 中獲取一個eventType(即訂閱方法的入?yún)㈩愋?為key的CopyOnWriteArrayList<Subscription>集合,沒有則創(chuàng)建,并放入subscriptionsByEventType中*/
        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);
            }
        }
        // 判斷訂閱方法優(yōu)先級并進行排序
        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;
            }
        }
        // 對typesBySubscriber集合進行添加
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
        // 判斷該訂閱方法是否是對sticky事件進行的訂閱,最后會分析,粘性事件會在訂閱之后立刻被分發(fā)
        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);
            }
        }
    }

至此EventBus.getDefault().register(this)分析結(jié)束,流程經(jīng)歷了EventBus的單例創(chuàng)建(包括了一些集合的初始化),通過反射分析訂閱對象的class對象獲取訂閱方法集合,再把訂閱方法集合的字段信息填充到EventBus的集合中.

EventBus.getDefault().post(new MessageEvent())
    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };


    public void post(Object event) {
        // 分析點1
        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);// 分析點2
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }


    /** For ThreadLocal, much faster to set (and get multiple values). */
    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<>();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        boolean canceled;
    }

分析點1中 currentPostingThreadState 是一個 ThreadLocal 對象,存儲了線程相關(guān)的變量 PostingThreadState 實例,而PostingThreadState 相對于一個實體類,存儲一些字段信息,其中最重要的是一個eventQueue線性表.而傳入的event正是加入到了這個eventQueue中.

經(jīng)過狀態(tài)和線性表長度判斷后調(diào)用了postSingleEvent也就是分析點2

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        /* 取出event的class類型后,對eventInheritance 標(biāo)志位判斷酣藻,它默認(rèn)為true,如果設(shè)為 true 的話观蜗,它會在發(fā)射事件的時候判斷是否需要發(fā)射父類事件*/
        if (eventInheritance) {
            // 取出 Event 及其父類和接口的 class 列表
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                // 分析點3
                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);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }


    // 分析點3
    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            // 根據(jù)event的class類型獲取訂閱了該event的訂閱對象和訂閱方法的封裝類 Subscription 的線性表集合
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted;
                try {
                    // 分析點4 遍歷subscriptions調(diào)用postToSubscription方法
                    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;
    }

    
    // 分析點4
    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);
        }
    }

重要的方法已經(jīng)注釋了,接下來看下分析點3 postSingleEventForEventType 方法,它做的就是根據(jù)event的類型獲取訂閱了該類型的訂閱者集合然后遍歷調(diào)用postToSubscription方法(也就是分析點4)

分析點4根據(jù)@Subscribe注釋的threadmode值,判斷如何調(diào)用訂閱方法

  1. POSTING:執(zhí)行 invokeSubscriber() 方法臊恋,內(nèi)部直接采用反射調(diào)用.
  2. MAIN:判斷當(dāng)前是否是UI 線程,是則直接反射調(diào)用墓捻,否則調(diào)用mainThreadPoster的enqueue()方法(即把當(dāng)前的方法加入到隊列之中抖仅,然后通過 handler 去發(fā)送一個消息,在 handler 的 handleMessage 中去執(zhí)行方法,分析過了)砖第。
  3. MAIN_ORDERED:確保是順序執(zhí)行的,與Main類似撤卢。
  4. BACKGROUND:判斷當(dāng)前是否在 UI 線程,不是則直接反射調(diào)用梧兼,否則通過backgroundPoster的enqueue()方法將方法加入到后臺的一個隊列放吩,最后通過線程池去執(zhí)行(已分析,可以查看上文回顧).
  5. ASYNC:邏輯實現(xiàn)類似于BACKGROUND,將任務(wù)加入到后臺的一個隊列羽杰,最終由線程池去調(diào)用渡紫,即Executors的newCachedThreadPool()方法創(chuàng)建的線程池(已分析,可以查看上文回顧)。
EventBus.getDefault().unregister(this)
    public synchronized void unregister(Object subscriber) {
        // 取出該訂閱者(object)訂閱的事件的class集合
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                // 分析點1 遍歷集合調(diào)用unsubscribeByEventType(subscriber, eventType)
                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) {
        // 取出訂閱了事件類型的所有訂閱對象和訂閱方法的封裝類 Subscription 的集合
        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);
                // 遍歷集合 當(dāng)該封裝類是需要取消注冊的訂閱者時,從Subscription集合中剔除
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

unregister的流程相對簡單只是對EventBus中的一些集合中需要取消注冊的元素的剔除.

EventBus.getDefault.postSticky(new MessageEvent())

最后來看看粘性事件

    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
        // 分析點1
        post(event);
    }

分析點1的post(event)走的是正常的post流程,也就是上面已經(jīng)分析過的流程.那么如何確保粘性事件會被事件發(fā)送后才訂閱的訂閱者接收,這其實是在訂閱者register流程中實現(xiàn)的.還記得register流程最后調(diào)用的 subscribe 方法中的分析嗎?

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    ...
        
    // 判斷該訂閱方法是否是對sticky事件進行的訂閱,最后會分析,粘性事件會在訂閱之后立刻被分發(fā)
    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>).
            // 分析點2
            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();
                    // 分析點3
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
}

分析點2遍歷 stickyEvents 集合,如果訂閱者的訂閱方法的入?yún)㈩愋秃?stickyEvents 集合中某個元素相同,則調(diào)用 checkPostStickyEventToSubscription 方法.

    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.
            // post流程中最后的調(diào)用方法
            postToSubscription(newSubscription, stickyEvent, isMainThread());
        }
    }

checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) 也就是分析點3最后也是調(diào)用post流程中的最后的調(diào)用方法(已分析).

總結(jié)

自此EventBus3.0的簡單使用的流程也就走通了,核心還是通過反射獲取訂閱者注解的訂閱方法,根據(jù)注解的參數(shù)以及訂閱方法的參數(shù)實現(xiàn)事件分發(fā)后訂閱者的訂閱操作.當(dāng)然還有一些優(yōu)先級和粘性事件的設(shè)計,總的來說這是一個設(shè)計得很棒的第三方庫.第三方庫源碼的詳細(xì)分析終究只是走一遍設(shè)計的流程.了解設(shè)計的思想才是重點,細(xì)節(jié)則不必太過糾結(jié).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末考赛,一起剝皮案震驚了整個濱河市惕澎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌颜骤,老刑警劉巖唧喉,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異忍抽,居然都是意外死亡八孝,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門鸠项,熙熙樓的掌柜王于貴愁眉苦臉地迎上來干跛,“玉大人,你說我怎么就攤上這事祟绊÷ト耄” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵久免,是天一觀的道長。 經(jīng)常有香客問我音诈,道長雹舀,這世上最難降的妖魔是什么淑廊? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮呼巴,結(jié)果婚禮上泽腮,老公的妹妹穿的比我還像新娘。我一直安慰自己衣赶,他們只是感情好诊赊,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著府瞄,像睡著了一般碧磅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上遵馆,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天鲸郊,我揣著相機與錄音,去河邊找鬼货邓。 笑死秆撮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的换况。 我是一名探鬼主播职辨,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼戈二!你這毒婦竟也來了舒裤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挽拂,失蹤者是張志新(化名)和其女友劉穎惭每,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亏栈,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡台腥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了绒北。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黎侈。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖闷游,靈堂內(nèi)的尸體忽然破棺而出峻汉,到底是詐尸還是另有隱情,我是刑警寧澤脐往,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布休吠,位于F島的核電站,受9級特大地震影響业簿,放射性物質(zhì)發(fā)生泄漏瘤礁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一梅尤、第九天 我趴在偏房一處隱蔽的房頂上張望柜思。 院中可真熱鬧岩调,春花似錦、人聲如沸赡盘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陨享。三九已至葱淳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間霉咨,已是汗流浹背蛙紫。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留途戒,地道東北人坑傅。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像喷斋,于是被迫代替她去往敵國和親唁毒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354