Eventbus 3.1.1 源码解析(二)

2019-03-10  本文已影响0人  LouisXWB

接着上篇文章,继续对Eventbus的源码进行解析

3.3 EventBus post(Object subscriber)

在介绍基本使用时,我们已经知道了发送事件是使用post(Object subscriber),接下来我们来分析一下它的源码:

/** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        //得到当前线程的postingState
        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;
            }
        }
    }

通过ThreadLocal<PostingThreadState> currentPostingThreadState获取当前的postingState,关于ThreadLocal,它是一个线程内数据存储类,它的作用域只在线程内部,支持在指定线程内进行存储和读取数据,Android消息机制中,MessageQueue就是使用ThreadLocal来存储数据。

因此,通过获取到的postingState就是当前线程保存的部分数据,参数如下:

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

接着,我们来看下发送单个事件的方法postSingleEvent(eventQueue.remove(0), postingState) 是如何实现的:

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);
                 //下面这句代码的理解是,只要有一个返回true,subscriptionFound就为true
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        
        //如果没有找到订阅者,则根据初始的配置,判断是否进行日志信息打印和NoSubscriberEvent事件发送
        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));
            }
        }
    }

接着我们继续看下发送方法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;
    }

上面的方法就是通过找到事件的订阅者,然后向每个订阅者进行事件发送,如果成功发送则返回true,没有找到订阅者或者事件被取消则返回false。

接着,我们继续看下事件是如何传递给订阅者的,

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

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

通过反射找到订阅者方法,然后传入对应的事件执行订阅逻辑,到此,发送事件的流程也解析完毕,整体流程如下:


post-flow-chart.png

3.4 unregister(Object subscriber)

最后,我们看看整个流程的最后一步,解除注册unregister(Object subscriber)的解析:

 /** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        //通过订阅者找到订阅的事件类型list
        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 == s ubscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

上面的解除注册方法就是找到订阅者订阅的所有事件,依次遍历,移除每个事件与订阅者的关联,最后把订阅者对应订阅事件的缓存也清除,防止内存泄露的发生。

至此,Eventbus的源码已经分析得差不多,后面对分析它整体的设计,思考我们可以学习和借鉴的地方。

上一篇下一篇

猜你喜欢

热点阅读