EventBus3.0源碼分析(二)post

距離上篇整整兩個月了,忙不是借口,反省。

上一篇文章介紹了register的過程,這篇接著來,一起看看EventBus發(fā)送事件的過程。EventBus可以通過post發(fā)送普通事件,還可以通過postSticky發(fā)送粘性事件。粘性事件與普通事件的區(qū)別在于:當(dāng)粘性事件發(fā)布后,若有訂閱者訂閱該事件,該訂閱者依然能收到最近一個該事件, 這點(diǎn)在上篇最后有提到。有了這個最基本的認(rèn)識,我們來看看這兩個方法的具體實(shí)現(xiàn)。

先瞅瞅發(fā)送普通事件post方法的源碼

public void post(Object event) {
    // 獲取當(dāng)前線程的PostingThreadState
    PostingThreadState postingState = currentPostingThreadState.get();
    // 事件隊列
    List<Object> eventQueue = postingState.eventQueue;
    // 添加到事件隊列中
    eventQueue.add(event);
    // 如果沒有發(fā)送事件,則將事件隊列中的事件一一發(fā)送出去
    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;
        }
    }
}

簡單說一下post的流程:先獲取當(dāng)前調(diào)用post方法的PostingThreadState,并將該事件添加到事件隊列中,如果當(dāng)前沒有發(fā)送事件, 則通過postSingleEvent方法將隊列中的事件一一發(fā)送出去。

繼續(xù)分析postSingleEvent方法

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    // 獲取該事件的class
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
  // 是否支持事件繼承(默認(rèn)是支持的)
    if (eventInheritance) {
        // 查找所有跟eventClass相關(guān)的類(包括eventClass實(shí)現(xiàn)的接口以及父類)
        // 若是第一次發(fā)送eventClass,通過api獲取其父類及其實(shí)現(xiàn)接口的集合,并放入map中緩存,
       //  第二次直接從map中取
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
             // 發(fā)送事件
            subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
        //  發(fā)送事件
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    if (!subscriptionFound) {
        // 默認(rèn)情況下, 如果沒有訂閱者訂閱該事件, 則打印如下信息,并且發(fā)送NoSubscriberEvent事件
        if (logNoSubscriberMessages) {
            Log.d(TAG, "No subscribers registered for event " + eventClass);
        }
 
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}

繼續(xù)簡單的說下上述postSingleEvent過程: 先判斷是否支持事件繼承,(默認(rèn)情況下支持)如果支持,則尋找此事件對應(yīng)類所有的父類,以及實(shí)現(xiàn)的接口,并發(fā)送。如果不支持,則僅發(fā)送此事件。 換句話說,如果支持事件繼承, 訂閱者訂閱該事件的父類,或者其實(shí)現(xiàn)的接口,都能接受到該事件。寫了個小demo大家看看:child 繼承parent,并且實(shí)現(xiàn)了interfaceA,interfaceB

public class Child extends Parent implements interfaceA, interfaceB {
}

// 發(fā)送child事件,則訂閱了其父類或者其實(shí)現(xiàn)接口的訂閱者,都能接受child事件
@Subscribe(threadMode = ThreadMode.MAIN)
 public void onInterfaceAEvent(interfaceA a) {
    Log.i(TAG, "onInterfaceAEvent: " + a.toString());
 }
@Subscribe(threadMode = ThreadMode.MAIN)
public void onInterfaceBEvent(interfaceB b) {
    Log.i(TAG, "onInterfaceBEvent: " + b.toString());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onParrentEvent(Parent p) {
    Log.i(TAG, "onParrentEvent: " + p.toString());
}

@Subscribe(threadMode = ThreadMode.MAIN)
public void onChildEvent(Child c) {
    Log.i(TAG, "onChildEvent: " + c.toString());
}

postSingleEvent中真正發(fā)送事件的方法是postSingleEventForEventType,我們繼續(xù)查看該方法干了什么勾當(dāng):

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

上述方法主要取得訂閱了eventClass的訂閱者集合,并且通過postToSubscription在指定的線程回調(diào)訂閱方法:

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
  // 訂閱者的訂閱方法需要在哪個線程調(diào)用
    switch (subscription.subscriberMethod.threadMode) {
        // 在調(diào)用post的線程,則直接調(diào)用訂閱方法
        case POSTING:
            invokeSubscriber(subscription, event);
            break;
        case MAIN:
            // 需要在主線程回調(diào),并且調(diào)用post的線程也是主線程,則直接調(diào)用訂閱方法
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                 // 需要在主線程回調(diào),調(diào)用post的線程不是主線程,則通過mainThreadPoster切換到主線程
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BACKGROUND:
             // 需要在非主線程回調(diào),調(diào)用post的線程也是主線程,則通過backgroundPoster切換到子線程
            if (isMainThread) {
                backgroundPoster.enqueue(subscription, event);
            } else {
                 // 需要在非主線程回調(diào),并且調(diào)用post的線程也是非主線程,則直接調(diào)用訂閱方法
                invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC:
            // 不論調(diào)用post的線程是否為主線程,都使用一個空閑線程來處理
            asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
    }
}

至此,整個post過程也就結(jié)束了。

至于postSticky只是比post多了一個步奏,在發(fā)布事件之前,先將該事件放入粘性事件集合stickyEvents(事件類型作為key,具體事件作為value)中,當(dāng)有訂閱者訂閱該事件并且注明接受粘性事件看,則能接收到最近的一個該事件。

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

最后借用網(wǎng)絡(luò)上的一幅圖來總結(jié)整個post流程:

post流程
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容