android组件化通信之EventBus粘性事件解析

背景

最近项目做组件化,需要进行组件化的通信,有时候可能会出现异步的情况,事件接收方还没准备好事件就已经发送过来了。这时候想到了EventBus的粘性事件。什么是粘性事件呢,通俗点讲就是不达目的不罢休的事件,事件保证能发送到订阅者手里。

发送粘性事件

EventBus发送粘性事件非常简单,一段代码就可以搞定:

EventBus.getDefault().postSticky(event)

接收粘性事件

接收粘性事件也非常简单,注册方法上加个sticky = true即可

@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
 public void  loginSuccessEvent(event: LoginSuccessEvent){}

粘性事件代码解析

一行代码就能实现这件神奇的事情,那么中间到底发生了什么呢,下面我们分析下源码:

 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出去。
stickyEvents是一个Map集合,加入这个集合里面会发生什么呢?

 private final Map, Object> stickyEvents;

通过跟踪我们会发现以下代码

 public void register(Object subscriber) {
        Class subscriberClass = subscriber.getClass();
        List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

    // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
      ....省略N段代码...
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
                // Existing sticky events of all subclasses of eventType have to be considered.
                // Note: Iterating over all events may be inefficient with lots of sticky events,
                // thus data structure should be changed to allow a more efficient lookup
                // (e.g. an additional map storing sub classes of super classes: Class -> List).
                Set, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry, Object> entry : entries) {
                    Class candidateEventType = entry.getKey();
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }

从上面可以看出在register事件的时候回调用subscribe方法,在subscribe中会处理stickyEvents中的粘性事件通过checkPostStickyEventToSubscription方法发送出去,继续跟踪发现最终都会走到下面这个方法里面

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

subscription.subscriberMethod.method.invoke(subscription.subscriber, event)就是执行在订阅者那边定义的处理事件的方法,至此整个流程就结束了。
看到这里想必大家都发现了,粘性事件有可能会收到两次,注意我这里用的是有可能。
让我们分析以下两种场景:
第一种订阅者Activity已经启动了,这时候事件通过postSticky之后调用post发送,而stickyEvents中缓存的事件不会发送,这是为什么呢。前面分析stickyEvents中事件的处理是在事件register的时候,而这时候粘性事件还没有发送所以只会发送一次。
第二种订阅者Activity还没启动但是粘性事件发送了,这时候通过post方式发送的消息是收不到的,然后当订阅者Activity中register事件时就会再发送一遍粘性事件。
综述,最终事件只会发送一遍。

你可能感兴趣的:(android组件化通信之EventBus粘性事件解析)