美文网首页Android开发Android知识
EventBus3.0源码分析(二)post

EventBus3.0源码分析(二)post

作者: static_sadhu | 来源:发表于2017-04-16 23:51 被阅读57次

    距离上篇整整两个月了,忙不是借口,反省。

    上一篇文章介绍了register的过程,这篇接着来,一起看看EventBus发送事件的过程。EventBus可以通过post发送普通事件,还可以通过postSticky发送粘性事件。粘性事件与普通事件的区别在于:当粘性事件发布后,若有订阅者订阅该事件,该订阅者依然能收到最近一个该事件, 这点在上篇最后有提到。有了这个最基本的认识,我们来看看这两个方法的具体实现。

    先瞅瞅发送普通事件post方法的源码

    public void post(Object event) {
        // 获取当前线程的PostingThreadState
        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的流程:先获取当前调用post方法的PostingThreadState,并将该事件添加到事件队列中,如果当前没有发送事件, 则通过postSingleEvent方法将队列中的事件一一发送出去。

    继续分析postSingleEvent方法

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        // 获取该事件的class
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
      // 是否支持事件继承(默认是支持的)
        if (eventInheritance) {
            // 查找所有跟eventClass相关的类(包括eventClass实现的接口以及父类)
            // 若是第一次发送eventClass,通过api获取其父类及其实现接口的集合,并放入map中缓存,
           //  第二次直接从map中取
            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) {
            // 默认情况下, 如果没有订阅者订阅该事件, 则打印如下信息,并且发送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));
            }
        }
    }
    

    继续简单的说下上述postSingleEvent过程: 先判断是否支持事件继承,(默认情况下支持)如果支持,则寻找此事件对应类所有的父类,以及实现的接口,并发送。如果不支持,则仅发送此事件。 换句话说,如果支持事件继承, 订阅者订阅该事件的父类,或者其实现的接口,都能接受到该事件。写了个小demo大家看看:child 继承parent,并且实现了interfaceAinterfaceB

    public class Child extends Parent implements interfaceA, interfaceB {
    }
    
    // 发送child事件,则订阅了其父类或者其实现接口的订阅者,都能接受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中真正发送事件的方法是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;
    }
    

    上述方法主要取得订阅了eventClass的订阅者集合,并且通过postToSubscription在指定的线程回调订阅方法:

    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
      // 订阅者的订阅方法需要在哪个线程调用
        switch (subscription.subscriberMethod.threadMode) {
            // 在调用post的线程,则直接调用订阅方法
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                // 需要在主线程回调,并且调用post的线程也是主线程,则直接调用订阅方法
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                     // 需要在主线程回调,调用post的线程不是主线程,则通过mainThreadPoster切换到主线程
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND:
                 // 需要在非主线程回调,调用post的线程也是主线程,则通过backgroundPoster切换到子线程
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                     // 需要在非主线程回调,并且调用post的线程也是非主线程,则直接调用订阅方法
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                // 不论调用post的线程是否为主线程,都使用一个空闲线程来处理
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }
    

    至此,整个post过程也就结束了。

    至于postSticky只是比post多了一个步奏,在发布事件之前,先将该事件放入粘性事件集合stickyEvents(事件类型作为key,具体事件作为value)中,当有订阅者订阅该事件并且注明接受粘性事件看,则能接收到最近的一个该事件。

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

    最后借用网络上的一幅图来总结整个post流程:

    post流程

    相关文章

      网友评论

        本文标题:EventBus3.0源码分析(二)post

        本文链接:https://www.haomeiwen.com/subject/vlczattx.html