EventBus第三章 :源码阅读与理解

EventBus第三章:事件的发送,调用和解绑

该篇我将继续讲解EventBus事件发送,调用和解绑,接下来进入今天的源码解析之路。

EventBus的发送

EventBus.getDefault().post(new TestEvent("hello Eventbus"));
EventBus.getDefault().postSticky(new TestEvent("hello sticky Eventbus"));

EventBus发送事件有两种方式,分别为post和postSticky,首先从post开始:

/** Posts the given event to the event bus. */
    /**
     *发送事件第一步:发布给定的事件到事件总线
     */
    public void post(Object event) {
        //获得一个PostingThreadState对象
        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;
            }
        }
    }

通过ThreadLocal.get()获取一个PostingThreadState对象,PostingThreadState是EventBus的一个内部类,用来判断一些订阅的操作,比如是否发送,是否在主线程等。调用eventQueue.add(event)将事件添加到集合中,postingState.isPosting判读该事件是否已经发送,若没有则继续执行,若集合不为null,则执行postSingleEvent方法,传递事件和postingState对象。finnally中对postingState对象的参数进行重置,对象进行重用。

/**
     *发送事件第二步:循环遍历订阅参数及其超类添加到集合中
     */
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        //获取订阅方法参数类型
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        //默认eventInheritance=true 执行这里
        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) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

根据发送的事件获取订阅参数类型,调用lookupAllEventTypes方法获取所有关联的订阅参数,这里的集合包含了父类和接口等。集合循环遍历每一个订阅参数类型,调用postSingleEventForEventType方法继续执行。

/**
     *发送事件第三部:根绝订阅参数类获取订阅者集合,遍历调用订阅类的订阅方法
     */
    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        //根据订阅参数获取subscriptions列表
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            //循环遍历每一个subscription对象,调用其中订阅类的订阅方法
            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集合中获取Subscription集合,循环遍历每一个Subscription对象,对postingState一些对象进行赋值,然后调用postToSubscription调起具体的订阅方法。finally中对postingState的变量进行重置。这里的返回值表示的是否找到订阅方法,若返回 false,并不会报错,需要注意下。我们也可以看到postingState对象主要就是用于对一些状态的判断,以及传递事件是否在主线程执行。接下来看一下具体的代码。

 /**
     *根据订阅方法的threadMode,在不同的线程调起订阅方法
     */
    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:
                //与MAIN的区别在于,MAIN_ORDERED会直接入队,有序排队等待处理,
                //若post在主线程,则直接掉起订阅方法,不入队,若post在子线程,则入队处理
                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);
        }
    }

在这里要根据设置的threadMode来决定最终在哪里调起订阅方法,POSTING代表在哪里发送就在哪里调用,所以这里直接调用invokeSubscriber方法。MAIN和MAIN_ORDER的区别主要在于:若是在子线程中发送事件,则两者是一样的都会调用mainThreadPoster执行Handler的事件处理操作,若是在主线程中则MAIN会直接调用invokeSubscriber方法,不需要执行入队操作。至于BACKGROUND和ASYNC都在子线程中调起订阅方法,不同的在于后者是不同步的。

eventBus.invokeSubscriber(pendingPost);

/**
     *通过Method反射invoke(调用)订阅类中的订阅方法
     */
    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);
        }
    }

最终通过反射来调起订阅方法,接下来看一次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);
    }

会发现首先将粘性事件存储到stickyEvents集合中,那么当我们注册粘性事件的时候,就会从该集合中查找看是否有符合的事件,其余的操作与post一致,不再讲解。

EventBus的解绑

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


 /**
     *根据订阅类和订阅参数类型移除数据
     */
    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 == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

这里首先根据解绑的订阅类从typesBySubscriber集合中获取订阅参数集合,然后调用unsubscribeByEventType方法根据订阅参数查找到所有符合条件的订阅类集合,从中移除需要解绑的订阅类,最后根据订阅类从typesBySubscriber集合中移除 所有属于该类的订阅参数数据。可以看到解绑还是比较简单的。

到这里关于EventBus的源码解析就差不多了,后面有时间还会出一些关于3.0后的订阅下标的使用和在源码的理解中学到了什么。避开误区,了解原理以及借鉴其设计模式和思想

你可能感兴趣的:(Android源码阅读系列)