EvenBus for Android 之 事件发布

事件的发表主要是调用EvenBus类的post方法,先来看下这个方法的实现

public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        if (postingState.isPosting) {
            return;
        } else {
            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;
            }
        }
    }

currentPostingThreadState 是ThreadLocal类,用于同一个线程的数据的共享。当发布事件时,会先把事件存储在eventQueue事件队列中。如果当前正在发布事件,则不需要自己处理,由其他程序来发布。

  try {
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }

通过不断的循环从队列中获取每个事件,调用postSingleEvent发送单个事件。再来看下postSingleEvent方法

 private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<? extends Object> eventClass = event.getClass();
        List<Class<?>> eventTypes = findEventTypes(eventClass);
        boolean subscriptionFound = false;
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            CopyOnWriteArrayList<Subscription> subscriptions;
            synchronized (this) {
                subscriptions = subscriptionsByEventType.get(clazz);
            }
            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;
                    }
                }
                subscriptionFound = true;
            }
        }
        if (!subscriptionFound) {
            Log.d(TAG, "No subscribers registered for event " + eventClass);
            if (eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

在subscriptionsByEventType中获取监听该事件的订阅者列表,在发送给具体订阅者时记录事件和订阅者到postingThreadState中,在通过postToSubscription方法通知到具体的订阅者。

在来看下postToSubscription的实现

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
        case PostThread:
            invokeSubscriber(subscription, event);
            break;
        case MainThread:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case BackgroundThread:
            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);
        }
    }

判断订阅者的类型判断是PostThread、MainThread、BackgroundThread、还是Async

类型为PostThread时(订阅者将在发起事件的同一个线程中执)直接调用invokeSubscriber方法

 void invokeSubscriber(Subscription subscription, Object event) throws Error {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException e) {
            Throwable cause = e.getCause();
            if (event instanceof SubscriberExceptionEvent) {
                // Don't send another SubscriberExceptionEvent to avoid infinite event recursion, just log
                Log.e(TAG, "SubscriberExceptionEvent subscriber " + subscription.subscriber.getClass()
                        + " threw an exception", cause);
                SubscriberExceptionEvent exEvent = (SubscriberExceptionEvent) event;
                Log.e(TAG, "Initial event " + exEvent.causingEvent + " caused exception in "
                        + exEvent.causingSubscriber, exEvent.throwable);
            } else {
                if (logSubscriberExceptions) {
                    Log.e(TAG, "Could not dispatch event: " + event.getClass() + " to subscribing class "
                            + subscription.subscriber.getClass(), cause);
                }
                SubscriberExceptionEvent exEvent = new SubscriberExceptionEvent(this, cause, event,
                        subscription.subscriber);
                post(exEvent);
            }
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }

就直接利用反射调用订阅者方法。

类型为MainThread时(订阅者将在主线程中执行),如果发起的线程是主线程,则直接调用invokeSubscriber方法。否则发送给mainThreadPoster。

mainThreadPoster就是一个Handler,里面最主要的就是维护了一个队列PendingPostQueue,这里介绍一下EvenBus定义了两个模型PendingPost和PendingPostQueue

PendingPost有一个静态的列表pendingPostPoo,用于存储PendingPost对象l,类似于线程池的作用,当事件发送完后,会把pendingPost的属性制null,而pendingPost对象则存到pendingPostPool中,这样下次要发送事件时就不需要再new一个pendingpost对象,而是pengdingPostPool中取出再附上事件和订阅者。

PendingPostQueue,维护了一个链表,其中有两个属性 head 和tail 的pendingPost。

再回到mainThreadPoster的调用,把订阅者和事件封装成PendingPost对象,并加到PendingPostQueue队列中,并发送message。mainThreadPoster接收到消息后会遍历queue中的所有事件并调用EvenBus的invokeSubscriber方法通知给订阅者。

类型为BackgriundThread时(订阅者将在一个后台线程中执行,如果发送的线程不是主线程,则直接在发起时间的线程中执行,如果发送的线程是主线程,则会在唯一的一个后台线程中按照顺序来执行所有的后台时间响应函数

如果不是主线程则直接调用invokeSubscriber方法。如果是主线程发送给backgroundPoster。

backgroundPoster继承于Runnable,EventBus定义的一个线程,把订阅者和事件封装成PendingPost对象后加入到PendingPostQueue中,再在线程中批量执行invokeSubscriber方法。

类型为Async时(订阅者将在另一个异步线程中执行),发送给asyncPoster,asyncPoster与backgroundPoster基本一样,也是继承与Runnable,不过他每次只执行队列中的一个事件而非批量执行。

EvenBus对于订阅者可以定义其类型是否为sticky,如果是,则订阅者在注册的时候Evenbus就会发送给他上一次发送的事件。当然只有调用postSticky发送的事件才会存储其事件,用于发送给刚注册的订阅者。





转载于:https://my.oschina.net/u/134491/blog/335434

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值