EventBus 线程切换原理
主要问题其实只有两个,其一:如何判断当前发送事件的线程是否是主线程;其二:如何在接收事件时指定线程并执行;
一个一个来看。
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 线程切换原理的更多相关文章
- Android的Handler线程切换原理
Handler是我们在开发中经常会接触到的类,因为在Android中,子线程一般是不能更新UI的. 所以我们会使用Handler切换到主线程来更新UI,那Handler是如何做到实现不同线程之间的切换 ...
- EventBus 消息的线程切换模型与实现原理
一. 序 EventBus 是一个基于观察者模式的事件订阅/发布框架,利用 EventBus 可以在不同模块之间,实现低耦合的消息通信. EventBus 因为其使用简单且稳定,被广泛应用在一些生产项 ...
- Java多线程系列--“JUC线程池”04之 线程池原理(三)
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...
- java多线程系列(六)---线程池原理及其使用
线程池 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知 ...
- java线程池原理
在什么情况下使用线程池? 1.单个任务处理的时间比较短 2.将需处理的任务的数量大 使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 ...
- 浅谈linux线程切换问题
http://www.jb51.net/article/102059.htm 处理器总处于以下状态中的一种: 1.内核态,运行于进程上下文,内核代表进程运行于内核空间 2.内核态,运行于中断上下文,内 ...
- juc线程池原理(四): 线程池状态介绍
<Thread之一:线程生命周期及五种状态> <juc线程池原理(四): 线程池状态介绍> 线程有5种状态:新建状态,就绪状态,运行状态,阻塞状态,死亡状态.线程池也有5种状态 ...
- linux线程切换问题
处理器总处于以下状态中的一种: 1.内核态,运行于进程上下文,内核代表进程运行于内核空间: 2.内核态,运行于中断上下文,内核代表硬件运行于内核空间: 3.用户态,运行于用户空间: 一个进程的上下 ...
- Java线程池原理解读
引言 引用自<阿里巴巴JAVA开发手册> [强制]线程资源必须通过线程池提供,不允许在应用中自行显式创建线程. 说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销 ...
随机推荐
- JavaScript大师必须掌握的12个知识点
既然你对这篇文章感兴趣,我想你应该是一位前端开发,也许你有一份不错的工作.自主创业甚至是一位自由从业者.不知你的前端技术如何,也许你是一位新手,亦或是一位资深开发. 如果你想让自己成为一个 JavaS ...
- Spring Boot统一异常处理实践
摘要: SpringBoot异常处理. 原文:Spring MVC/Boot 统一异常处理最佳实践 作者:赵俊 前言 在 Web 开发中, 我们经常会需要处理各种异常, 这是一件棘手的事情, 对于很多 ...
- 给zTree的treeNode添加class
onNodeCreated 回调,捕获 DOM 创建完毕的回调,然后利用 zTree 的规则找到 treeNode.tId + "_a" 这样的 标签,自行添加 class 就是了 ...
- 卷烟厂生产管理系统基于ASP.NET
VS.Net 2003开发的一个非常老的生产信息管理系统运行10多年依旧稳定,这几天来南昌做维保工作,看到了曾经开发的信息系统.该系统在我眼里老到几点,可却依然在厂里大面积使用,抛开技术上的落后,从新 ...
- QT之Http请求
今天我们介绍一下QT的http请求,这里有post和get两种方式 一.post请求方式:参数分为网址和具体请求值两个部分,有时候还需要设置头信息,看具体情况定 void MainWindow::se ...
- asp.net core自定义端口
asp.net Core 自定义端口 官方文档 aspnet内库源码: https://github.com/aspnet dotnet系统内库源码:https://github.com/dotnet ...
- MongoDB 提升性能的18原则(开发设计阶段)
MongoDB 是高性能数据,但是在使用的过程中,大家偶尔还会碰到一些性能问题.MongoDB和其它关系型数据库相比,例如 SQL Server .MySQL .Oracle 相比来说,相对较新,很多 ...
- python3 Counter类(计数器)
Counter(计数器):用于追踪值的出现次数 Counter类继承dict类,所以它能使用dict类里面的方法 创建一个Counter类 import collections obj = colle ...
- LeetCode算法题-Reverse Words in a String III(Java实现)
这是悦乐书的第259次更新,第272篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第126题(顺位题号是557).给定一个字符串,您需要反转句子中每个单词中的字符顺序,同 ...
- 基于DataTables实现根据每个用户动态显示隐藏列,可排序
前言 在后台管理系统开发中,难免会出现列数太多的情况,这里提供一个解决方案:用户设置显示哪些列,每个用户互不影响,并且可以根据用户的习惯设置列的排序. 1.演示 2.html代码说明 3.java ...