EventBus3.0源码分析(二)--发送流程

前言

之前介绍了EventBus的订阅流程,这回看一下事件的发送流程。

发送事件

EventBus发送事件有两种方式,

  • 普通的发送事件post()

  • 发送粘性事件postSticky()。

EventBus#post()

/** Posts the given event to the event bus. */
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;
        }
    }
}

以上代码中,首先从currentPostingThreadState里面取出发送状态,再从发送状态里面取出事件队列,将需要发送的事件(也就是参数传递的事件)加入到发送队列里面。

这里可以看出post()方法发送事件并不是直接调用就会发送的,而是将其加入到事件队列中去,再遍历事件队列按顺序调用postSingleEvent()发送事件。

PostingThreadState是一个记录发送状态的类,也就是记录一下发送的事件队列,是否是处于发送状态,是否在主线程,订阅关系等,源码如下:

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

EventBus#postSingleEvent()

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    if (eventInheritance) {
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            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()发送事件并返回结果。

如果事件不支持继承,则直接调用postSingleEventForEventType()方法发送事件。

最后判断发送结果,即是否有订阅关系,如果subscriptionFound为false,想当于发送失败,没有找到订阅关系,则发送一个NoSubscriberEvent(无订阅事件)。

EventBus#postSingleEventForEventType()

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

该方法中,从subscriptionsByEventType中取出订阅关系subscriptions,然后遍历该订阅关系,调用postToSubscription()方法去发送事件。

EventBus#postToSubscription()

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case PostThread:
            invokeSubscriber(subscription, event);
            break;
        case MainThread:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BackgroundThread:
            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);
    }
}

从stickyEvents中取出Event,根据他的ThreadMode去决定直接反射调用方法,还是将其插入队列。该方法在上篇博客中有提及。

EventBus#postSticky()

/**
 * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
 * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
 */
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,然后在调用post()方法去发送。