Android EventBus 源码分析

01.EventBus注册源码解析

1.1 EventBus.getDefault()获取对象

  • 先看源码,单例模式,使用了双重判断的方式,防止并发的问题,还能极大的提高效率

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
    if (defaultInstance == null) {
    synchronized (EventBus.class) {
    if (defaultInstance == null) {
    defaultInstance = new EventBus();
    }
    }
    }
    return defaultInstance;
    }
  • 接着看一下如何构造对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

    public EventBus() {
    this(DEFAULT_BUILDER);
    }

    EventBus(EventBusBuilder builder) {
    logger = builder.getLogger();
    subscriptionsByEventType = new HashMap<>();
    typesBySubscriber = new HashMap<>();
    stickyEvents = new ConcurrentHashMap<>();
    mainThreadSupport = builder.getMainThreadSupport();
    mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
    backgroundPoster = new BackgroundPoster(this);
    asyncPoster = new AsyncPoster(this);
    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
    builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    logSubscriberExceptions = builder.logSubscriberExceptions;
    logNoSubscriberMessages = builder.logNoSubscriberMessages;
    sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
    sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
    throwSubscriberException = builder.throwSubscriberException;
    eventInheritance = builder.eventInheritance;
    executorService = builder.executorService;
    }

1.2 register(this)注册源码解析

  • 首先看register(this)源码

    • 这里直接获取subscriber字节码对象。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public void register(Object subscriber) {
    //首先获取订阅者的类对象
    Class<?> subscriberClass = subscriber.getClass();
    //用 subscriberMethodFinder 提供的方法,找到在 subscriber 这个类里面订阅的内容。
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
    //
    for (SubscriberMethod subscriberMethod : subscriberMethods) {
    subscribe(subscriber, subscriberMethod);
    }
    }
    }
  • 接下来看findSubscriberMethods(subscriberClass)里面的源码

    • 该方法的作用其实就是从订阅类中获取所有的订阅方法信息
    • findSubscriberMethods找出一个SubscriberMethod的集合,也就是传进来的订阅者所有的订阅的方法,接下来遍历订阅者的订阅方法来完成订阅者的订阅操作。对于SubscriberMethod(订阅方法)类中,主要就是用保存订阅方法的Method对象、线程模式、事件类型、优先级、是否是粘性事件等属性。
    • 源码分析:首先从缓存中查找,如果找到了就立马返回。如果缓存中没有的话,则根据 ignoreGeneratedIndex 选择如何查找订阅方法,ignoreGeneratedIndex属性表示是否忽略注解器生成的MyEventBusIndex。最后,找到订阅方法后,放入缓存,以免下次继续查找。ignoreGeneratedIndex 默认就是false,可以通过EventBusBuilder来设置它的值。我们在项目中经常通过EventBus单例模式来获取默认的EventBus对象,也就是ignoreGeneratedIndex为false的情况,这种情况调用了findUsingInfo方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    //首先从缓存中读取
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
    return subscriberMethods;
    }
    //是否忽略注解器生成的MyEventBusIndex类
    if (ignoreGeneratedIndex) {
    //利用反射来获取订阅类中的订阅方法信息
    subscriberMethods = findUsingReflection(subscriberClass);
    } else {
    //从注解器生成的MyEventBusIndex类中获得订阅类的订阅方法信息
    subscriberMethods = findUsingInfo(subscriberClass);
    }

    //在获得subscriberMethods以后,如果订阅者中不存在@Subscribe注解并且为public的订阅方法,则会抛出异常。
    if (subscriberMethods.isEmpty()) {
    throw new EventBusException("Subscriber " + subscriberClass
    + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
    //保存进缓存
    METHOD_CACHE.put(subscriberClass, subscriberMethods);
    return subscriberMethods;
    }
    }
    //METHOD_CACHE,是一个map集合,键是class类型
    Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();
  • 接下来看findUsingInfo(subscriberClass)源码

    • 通过getSubscriberInfo方法来获取订阅者信息。在我们开始查找订阅方法的时候并没有忽略注解器为我们生成的索引MyEventBusIndex,如果我们通过EventBusBuilder配置了MyEventBusIndex,便会获取到subscriberInfo,调用subscriberInfo的getSubscriberMethods方法便可以得到订阅方法相关的信息,这个时候就不在需要通过注解进行获取订阅方法。如果没有配置MyEventBusIndex,便会执行findUsingReflectionInSingleClass方法,将订阅方法保存到findState中。最后再通过getMethodsAndRelease方法对findState做回收处理并反回订阅方法的List集合。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
    //获取订阅者信息,没有配置MyEventBusIndex返回null
    findState.subscriberInfo = getSubscriberInfo(findState);
    if (findState.subscriberInfo != null) {
    SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
    for (SubscriberMethod subscriberMethod : array) {
    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
    findState.subscriberMethods.add(subscriberMethod);
    }
    }
    } else {
    //通过反射来查找订阅方法
    findUsingReflectionInSingleClass(findState);
    }
    findState.moveToSuperclass();
    }
    return getMethodsAndRelease(findState);
    }

1.3 查找完所有的订阅方法后便开始对所有的订阅方法进行注册

  • 回到register(this)这个方法

    • image
  • 订阅者的注册过程

    • 订阅的代码主要就做了两件事,第一件事是将我们的订阅方法和订阅者封装到subscriptionsByEventType和typesBySubscriber中,subscriptionsByEventType是我们投递订阅事件的时候,就是根据我们的EventType找到我们的订阅事件,从而去分发事件,处理事件的;typesBySubscriber在调用unregister(this)的时候,根据订阅者找到EventType,又根据EventType找到订阅事件,从而对订阅者进行解绑。第二件事,如果是粘性事件的话,就立马投递、执行。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    //获取订阅方法的参数类型
    Class<?> eventType = subscriberMethod.eventType;
    //根据订阅者和订阅方法构造一个订阅事件
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    //获取当前订阅事件中Subscription的List集合
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    //该事件对应的Subscription的List集合不存在,则重新创建并保存在subscriptionsByEventType中
    if (subscriptions == null) {
    subscriptions = new CopyOnWriteArrayList<>();
    subscriptionsByEventType.put(eventType, subscriptions);
    } else {
    //订阅者已经注册则抛出EventBusException
    if (subscriptions.contains(newSubscription)) {
    throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
    + eventType);
    }
    }

    //遍历订阅事件,找到比subscriptions中订阅事件小的位置,然后插进去
    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
    if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
    subscriptions.add(i, newSubscription);
    break;
    }
    }

    //通过订阅者获取该订阅者所订阅事件的集合
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
    subscribedEvents = new ArrayList<>();
    typesBySubscriber.put(subscriber, subscribedEvents);
    }

    //将当前的订阅事件添加到subscribedEvents中
    subscribedEvents.add(eventType);
    if (subscriberMethod.sticky) {
    if (eventInheritance) {
    //粘性事件的处理
    Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
    for (Map.Entry<Class<?>, 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);
    }
    }
    }
  • 流程图

    • image

02.EventBus事件分发解析

2.1 从post方法入手

  • 首先从PostingThreadState对象中取出事件队列,然后再将当前的事件插入到事件队列当中。最后将队列中的事件依次交由postSingleEvent方法进行处理,并移除该事件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /** Posts the given event to the event bus. */
    public void post(Object event) {
    //获取当前线程的postingState
    PostingThreadState postingState = currentPostingThreadState.get();
    //取得当前线程的事件队列
    List<Object> eventQueue = postingState.eventQueue;
    //将该事件添加到当前的事件队列中等待分发
    eventQueue.add(event);
    if (!postingState.isPosting) {
    //判断是否是在主线程post
    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;
    }
    }
    }

2.2 什么是PostingThreadState?

  • PostingThreadState中包含了当前线程的事件队列,就是当前线程所有分发的事件都保存在eventQueue事件队列中以及订阅者订阅事件等信息,有了这些信息我们就可以从事件队列中取出事件分发给对应的订阅者

    1
    2
    3
    4
    5
    6
    7
    8
    final static class PostingThreadState {
    final List<Object> eventQueue = new ArrayList<Object>();//当前线程的事件队列
    boolean isPosting;//是否有事件正在分发
    boolean isMainThread;//post的线程是否是主线程
    Subscription subscription;//订阅者
    Object event;//订阅事件
    boolean canceled;//是否取消
    }

2.3 PostingThreadState怎么获得?

  • ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,而这段数据是不会与其他线程共享的。

    • 可以看出currentPostingThreadState的实现是一个包含了PostingThreadState的ThreadLocal对象,这样可以保证取到的都是自己线程对应的数据。
    • 我们有了PostingThreadState获取到了当前线程的事件队列,接下来就是事件分发,我们来看postSingleEvent(eventQueue.remove(0), postingState);
    1
    2
    3
    4
    5
    6
    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
    @Override
    protected PostingThreadState initialValue() {
    return new PostingThreadState();
    }
    };

2.4 来看看postSingleEvent方法里做了什么

  • eventInheritance表示是否向上查找事件的父类,它的默认值为true,可以通过在EventBusBuilder中来进行配置。当eventInheritance为true时,则通过lookupAllEventTypes找到所有的父类事件并存在List中,然后通过postSingleEventForEventType方法对事件逐一处理,接下来看看postSingleEventForEventType方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    事件分发
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    //得到事件类型
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;

    //是否触发订阅了该事件(eventClass)的父类,以及接口的类的响应方法.
    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));
    }
    }
    }

2.5 接下来看看postSingleEventForEventType方法

  • 同步取出该事件对应的Subscription集合并遍历该集合将事件event和对应Subscription传递给postingState并调用postToSubscription方法对事件进行处理,接下来看看postToSubscription方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    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;
    }

2.6 接下来看看postToSubscription方法

  • 源码如下所示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
    case POSTING://默认的 ThreadMode,表示在执行 Post 操作的线程直接调用订阅者的事件响应方法,
    //不论该线程是否为主线程(UI 线程)。
    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);
    }
    }

2.7 整个流程图

  • image

2.8 总结一下整个事件分发的过程

  • 大概如下所示:
    • 首先获取当前线程的PostingThreadState对象从而获取到当前线程的事件队列
    • 通过事件类型获取到所有订阅者集合
    • 通过反射执行订阅者中的订阅方法

03.EventBus取消注册解析

3.1 unregister(this)方法入手

  • 代码如下所示

    • 获取订阅者的所有订阅的事件类型,然后遍历事件类型的订阅者集合中移除订阅者
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /** Unregisters the given subscriber from all event classes. */
    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 {
    Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
    }

3.2 再来看看unsubscribeByEventType(subscriber, eventType)

  • 获取事件类型的所有订阅者,然后遍历订阅者集合,将解除的订阅者移除

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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--;
    }
    }
    }
    }

3.3 取消注册流程图

  • image

3.4 取消注册的过程

  • 总结一下取消注册的过程
    • 1、首先获取订阅者的所有订阅事件
    • 2、遍历订阅事件
    • 3、根据订阅事件获取所有的订阅了该事件的订阅者集合
    • 4、将该订阅者移除
    • 5、将步骤1中的集合中的订阅者移除

04.总结一下EventBus的工作原理

4.1 订阅逻辑

  • 逻辑如下所示:
    • 1、首先用register()方法注册一个订阅者
    • 2、获取该订阅者的所有订阅的方法
    • 3、根据该订阅者的所有订阅的事件类型,将订阅者存入到每个以 事件类型为key 以所有订阅者为values的map集合中
    • 4、然后将订阅事件添加到以订阅者为key 以订阅者所有订阅事件为values的map集合中
    • 5、如果是订阅了粘滞事件的订阅者,从粘滞事件缓存区获取之前发送过的粘滞事件,响应这些粘滞事件。

4.2 事件发送逻辑

  • 逻辑如下所示:
    • 1、首先获取当前线程的事件队列
    • 2、将要发送的事件添加到事件队列中
    • 3、根据发送事件类型获取所有的订阅者
    • 4、根据响应方法的执行模式,在相应线程通过反射执行订阅者的订阅方法

4.3 取消逻辑

  • 逻辑如下所示:
    • 1、首先通过unregister方法拿到要取消的订阅者
    • 2、得到该订阅者的所有订阅事件类型
    • 3、遍历事件类型,根据每个事件类型获取到所有的订阅者集合,并从集合中删除该订阅者
    • 4、将订阅者从步骤2的集合中移除