码迷,mamicode.com
首页 > 其他好文 > 详细

EventBus源码阅读(一)

时间:2016-04-17 16:01:01      阅读:216      评论:0      收藏:0      [点我收藏+]

标签:

  EventBus虽然有诸多缺点,但是作为一个经典的事件总线框架,其代码还是有一些学习价值,从他的代码中可以获得一些启发,运用于开发。

  EventBus有两个入口,一个是订阅,一个是发送事件。今天从发送事件开始阅读。

        EventBus.getDefault().post("11");

 

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

 

  post方法第一件事,就是获取当前posting的线程状态。并用一个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;
    }

 

  PostingThreadState这个类,是保存了一些状态。比如是否正在发送,是否在主线程工作,以及当前的订阅者和事件列表。

  post第二行就获取了事件列表——eventQueue。将此次post的事件,加入eventQueue。将下来的代码比较简单,只要postingState不是正在发送,就陆续把事件列表中的事件postSingleEvent出去,直到eventQueue为空为止。

 

  下面来看看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));
            }
        }
    }

 

  eventInheritance在源码中说明如下: 

    /**
     * By default, EventBus considers the event class hierarchy (subscribers to super classes will be notified).
     * Switching this feature off will improve posting of events. For simple event classes extending Object directly,
     * we measured a speed up of 20% for event posting. For more complex event hierarchies, the speed up should be
     * >20%.
     * <p/>
     * However, keep in mind that event posting usually consumes just a small proportion of CPU time inside an app,
     * unless it is posting at high rates, e.g. hundreds/thousands of events per second.
     */

 

  它决定了订阅者的父类是否接到通知,在默认情况下,是置为true的,我们可以手动设置,暂时不深究。

  所以我们先看

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

  通过lookupAllEventTypes获取eventClass的所有父类。然后通过轮循,对所有的类及父类进行发送事件。只要有一个类,有被订阅,则subscriptionFound为true。

  下面可以看到:

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

  如果没有找到订阅者,则直接打出Log。默认情况下,sendNoSubscriberEvent为true。因此,如果没有订阅者,将会发送一个NoSubscriberEvent事件。由此,我们可出postSingleEvent中核心方法是postSingleEventForEventType,因此,我们再去看看这个方法。

  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中,我们通过eventClass取出相应的订阅源,然后对订阅源调用 postToSubscription(subscription, event, postingState.isMainThread);方法。

  最后,postToSubscription方法,就会根据不同的线程模式,通过订阅源执行方法:

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

 

  除了,POSTING情况,其他情况,都各自有一个Poster来执行任务,它们分别是mainThreadPoster、backgroundPoster和asyncPoster。他们的具体实习,留作下一篇进行分析。

 

  至此,EventBus的事件发送,基本流程走通,只剩下两个没有深究的问题,一个是各式各样的Poster到底如何工作,另一个是eventInheritance的具体作用。这两个问题,下篇再阅读。

 

Done~

EventBus源码阅读(一)

标签:

原文地址:http://www.cnblogs.com/fishbone-lsy/p/5401148.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!