EventBus3.0源码解析-04

EventBus3.0源码解析-01这篇文章简单的介绍了EventBus的使用流程,我们知道EventBus有三个主要入口方法,分别为

  • EventBus.getDefault().register(Object); 
    
  • EventBus.getDefault().unregister(Object);
    
  • EventBus.getDefault().post(Object);
    

EventBus3.0源码解析-02这篇文章已经介绍了register的逻辑,本文将介绍post,unregister以及sticky事件的逻辑。

Post

post方法的实现如下:

public void post(Object event) {
	// 线程安全的变量
    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;
        }
    }
}

post方法里面的大多数逻辑通过看代码注释就能明白,我们这里主要介绍它的核心方法postSingleEvent(Object event, PostingThreadState postingState),该方法的实现如下:

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    // 是否考虑事件类的继承,默认false
    if (eventInheritance) {
        // 找到eventClass以及eventClass的父类以及接口
        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) {
            logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}

postSingleEvent方法的实现逻辑为,首先判断是否考虑事件类的继承,如果不考虑,则只通知订阅该event的方法。如果考虑事件类的继承,则会通知订阅该event以及该event的父类以及其实现的接口的所有方法。我们看一下postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass)方法的实现:

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(Subscription subscription, Object event, boolean 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);
    }
}

invokeSubscriber方法就是通过反射执行相应的订阅方法,各个ThreadMode的具体含义可以参考这篇文章

Unregister

unregister方法的实现如下:

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

这个方法的实现非常简单,就是将该订阅类的订阅信息从subscriptionsByEventType和typesBySubscriber变量中剔除。

Sticky事件

sticky事件的使用分为两步:

1、调用postSticky方法:

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

该方法首先将sticky事件保存在stickyEvents变量中,然后走正常的post事件流程。

2、当我们调用EventBus的register方法时,会执行以下逻辑:

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

如果不考虑事件类的继承关系,那么只是把stickyEvents中eventType拿出来进行通知,如果考虑继承,那么需要把stickyEvents中eventType以及eventType的子类事件都拿出来进行通知。checkPostStickyEventToSubscription方法就是调用上面介绍的postToSubscription方法。

如果大家看完我的本系列文章之后,对EventBus还有不明白的地方,请下载EventBus源码进行学习。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值