美文网首页
EventBus 事件线程切换原理

EventBus 事件线程切换原理

作者: zhangyu1991 | 来源:发表于2018-07-10 15:20 被阅读253次

今天学习了一下EventBus 的源码,将其在接收事件时指定线程执行的大致原理梳理了一下,提炼整理,作为学习总结,也方便日后查阅。

正文

EventBus 可以在不同的线程发送事件、并在指定类型的线程接收和处理事件。在不同线程情况下,发送、接收并处理事件大致有4种情况:
A:在主线程发送,在子线程发送;B:在主线程执行订阅方法,在子线程执行订阅方法;AB两两搭配会有四种组合,也就是在不同线程情况下,发送、接收并处理事件的4种情况。
主要的问题其实只有两个,其一:如何判断当前发送事件的线程是否是主线程;其二:如何在接收事件时指定线程并执行;
一个一个来看。

1.如何判断是否在主线程发送

EventBus在初始化的时候会初始化一个MainThreadSupport对象,它会去获取主线程的Looper对象并存起来。(当前最新版本如果不是Android环境MainThreadSupport会为空,非Android环境也就无需关注是否是UI主线程的问题了)
在发送消息的时候,EventBus会取出当前线程的Looper对象对象与主线程Looper对象做比较,如果相同,说明是在主线程发送消息,如果不同,说明是在子线程发送消息。以下是MainThreadSupport的代码:

public interface MainThreadSupport {

    boolean isMainThread();

    Poster createPoster(EventBus eventBus);

    class AndroidHandlerMainThreadSupport implements MainThreadSupport {

        private final Looper looper;

        public AndroidHandlerMainThreadSupport(Looper looper) {
            this.looper = looper;
        }

        @Override
        public boolean isMainThread() {
            return looper == Looper.myLooper();
        }

        @Override
        public Poster createPoster(EventBus eventBus) {
            return new HandlerPoster(eventBus, looper, 10);
        }
    }
}
2.怎么在指定的线程执行订阅者的方法

在找到订阅者之后,判断不同线程情况下执行订阅方法的逻辑基本都在postToSubscription()方法里面:

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

以上代码中,如何判断是否是主线程上面已经说过了。
invokeSubscriber()这个方法其实就是拿到订阅者的信息,直接执行订阅方法了(通过反射获取)。
subscription对象中有一个SubscriberMethod对象,而SubscriberMethod这个对象基本上包含了订阅者的执行线程、订阅方法、是否粘性事件、优先级等等信息。如下:

public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;
    //省略若干代码...
}

所以,从postToSubscription()方法可以看出,当threadMode是POSTING时,直接在当前线程执行,不做判断,也就是从哪个线程发送,就从哪个线程执行订阅方法;
我们这里主要来看threadMode为MAIN和BACKGROUND的情况:

在主线程执行

当threadMode为MAIN时,如果在主线程发送,直接在当前线程执行,没有问题。如果不在主线程发送,会有一个mainThreadPoster将包含订阅者信息的对象加入队列。这个mainThreadPoster其实是Handler的子类,它利用Handler的消息机制,发送消息并在主线程接收消息,获取到订阅者的信息后在主线程处理事件,从而实现在子线程发送消息,在主线程处理事件。
这里直接利用Hadler的现成机制,可谓简明高效。

在子线程执行

当threadMode为BACKGROUND时,如果不在主线程发送,直接执行,没有问题。如果在主线程发送,这里有一个backgroundPoster将包含订阅者信息的对象加入队列。BackgroundPoster其实是Runnable的子类,在自己的run方法中不断从队列中取出订阅者对象,执行订阅方法。EventBus维护了一个线程池,BackgroundPoster会将自己丢到线程池中,执行自己的run方法,从而实现在在主线程发送事件,在子线程中执行订阅方法。

以上,就是EventBus切换执行线程的主要流程。
其实并不难。
末尾附上一篇讲解EventBus原理的简练博文:戳这里

相关文章

  • EventBus 事件线程切换原理

    今天学习了一下EventBus 的源码,将其在接收事件时指定线程执行的大致原理梳理了一下,提炼整理,作为学习总结,...

  • EventBus框架初解

    EventBus其实解决了这样几个问题:保存订阅者、发布事件、切换线程、粘性事件 保存订阅者 在register(...

  • EventBus源码解析

    知识点汇总: 一:EventBus框架概述 二:EventBus的注册实现原理 三:EventBus的事件分发实现...

  • EventBus源码分析

    问题 使用限制 事件发送以及接收原理 设计模式 分析 EventBus#getDefault() EventBus...

  • 兄弟组件通讯

    eventBus 定义eventBus eventBus的原理是引入一个新的vue对象,分别调用这个对象的事件发布...

  • EventBus解析

    EventBus使用 EventBus是一个事件发布/订阅的框架,它能够简化各组件,异步线程和主线程的通信,Eve...

  • rxjava源码解析

    线程切换原理 案例 subscribeOn切换子线程 先看subscribe的执行,最后会执行Observable...

  • EventBus 源码分析

    EventBus原理解析 1. 注册EventBus 将一个类注册为事件的订阅者分两步 EventBus.getD...

  • EventBus

    EventBus:事件总线 用处:跨模块,跨线程通信 可以替代holder 三(4)要素: Event事件 su...

  • 一文分析EventBus 事件总线的使用方法和实现原理

    前言 本文主要从源码的角度来分析事件总线 EventBus 的实现原理, EventBus 是常用的消息传递的方式...

网友评论

      本文标题:EventBus 事件线程切换原理

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