当前位置: 首页 > news >正文

主线程与子线程之间相互通信(HandlerThread)

平时,我们一般都是在子线程中向主线程发送消息(要在主线程更新UI),从而完成请求的处理。那么如果需要主线程来向子线程发送消息,希望子线程来完成什么任务。该怎么做?这就是这篇文章将要讨论的内容。

一、HandlerThread类

      主线程发送消息给子线程,通常思维逻辑就是:创建子线程,在主线程中实例化一个与子线程Looper相关联的Handler,这样handler处理的消息就是该子线程中的消息队列,而处理的逻辑都是在该子线程中执行的,不会占用主线程的时间。

实践一下。新建项目,修改它的MainActivity的代码,如下即可:

public class ThreadHandlerActivity extends Activity{//创建子线程class MyThread extends Thread{private Looper looper;//取出该子线程的Looper@Overridepublic void run() {Looper.prepare();//创建该子线程的Looperlooper = Looper.myLooper();//取出该子线程的LooperLooper.loop();//只要调用了该方法才能不断循环取出消息}}private TextView tv;private MyThread thread;private Handler mHandler;//将mHandler指定轮询的Looperprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv = new TextView(this);tv.setText("Handler实验");setContentView(tv);thread = new MyThread();thread.start();//千万别忘记开启这个线程//下面是主线程发送消息mHandler = new Handler(thread.looper){@Overridepublic void handleMessage(android.os.Message msg) {Log.d("当前子线程是----->", Thread.currentThread()+"");};};mHandler.sendEmptyMessage(1);}}

现在运行该程序。并没有得到预期的结果呢,报错误如下:

这是一个空指针错误。当主线程走到mHandler = new Handler(thread.looper),此时子线程的Looper对象还没有被创建出来,那么此时thread.looper肯定为空了。

当然了,你可以让主线程休眠2秒后再执行后面的代码,但是如果有很多个子线程都需要主线程类给其分配任务怎么办??那简直要乱套了。所以需要一个更好的解决方式。Android显然也考虑到了这个问题,于是它我们提供了一个HandlerThread类。这个类是专门处理这个问题的。

当主线程中有耗时的操作时,需要在子线程中完成,通常我们就把这个逻辑放在HandlerThread的对象中执行(该对象就是一个子线程)一下就可以了。下面我们就修改上面的代码,看一看如何使用HandlerThread这个类。修改MainActivity中的代码如下:

public class ThreadHandlerActivity extends Activity{private TextView tv;private Handler mHandler;//将mHandler指定轮询的Looperprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv = new TextView(this);tv.setText("Handler实验");setContentView(tv);//实例化一个特殊的线程HandlerThread,必须给其指定一个名字HandlerThread thread = new HandlerThread("handler thread");thread.start();//千万不要忘记开启这个线程//将mHandler与thread相关联mHandler = new Handler(thread.getLooper()){public void handleMessage(android.os.Message msg) {Log.d("当前子线程是----->", Thread.currentThread()+"");};};mHandler.sendEmptyMessage(1);//发送消息}}

 运行程序,打印的结果如下:

     从打印结果来看,当前子线程的名字正是我们所起的那个名字“handler thread"。

     你会有疑问,表面上看HandlerThread并没有创建自己的Looper啊?而且既然是一个线程,那么我们肯定也能重写它的run方法吧。在解答你的疑问之前,我们不妨重写它的run方法来看一看会有什么结果。将代码修改如下:

public class ThreadHandlerActivity extends Activity{private TextView tv;private Handler mHandler;//将mHandler指定轮询的Looperprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv = new TextView(this);tv.setText("Handler实验");setContentView(tv);//实例化一个特殊的线程HandlerThread,必须给其指定一个名字HandlerThread thread = new HandlerThread("handler thread"){@Overridepublic void run() {for(int i=0;i<3;i++){Log.d("handler thread run ",i+"");}}};
//            HandlerThread thread = new HandlerThread("handler thread");thread.start();//千万不要忘记开启这个线程//将mHandler与thread相关联mHandler = new Handler(thread.getLooper()){public void handleMessage(android.os.Message msg) {Log.d("当前子线程是----->", Thread.currentThread()+"");};};mHandler.sendEmptyMessage(1);//发送消息}}

 红色部分就是我们重写了它的run方法。再云运行程序,打印的结果如下:

for循环的打印结果正常,但是为什么没有打印出”当前子线程“呢。其实这正是我们要解释的地方。查看HandlerThread的源代码,找到它的run方法,如下:

@Overridepublic void run() {mTid = Process.myTid();Looper.prepare();synchronized (this) {mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid = -1;}

可以知道,在run方法中实例化自己的Looper,如果继续追踪源代码翻看其getLooper方法你会发现,如果一个Handler在与HandlerThread进行绑定时,发现Looper为空,Handler则会一直等待直到Looper被创建出来为止,然后才继续执行后续的代码。所以我们重写了HandlerThread的run方法,肯定就不会去创建Looper对象,那么绑定的Handler就会永远处于等待状态,自然而然就不会打印出”当前子线程“信息了。这也是为什么我们要使用HandlerThread这个特殊的线程,因为使用这个,我们不必关心多线程会混乱,Looper会为空等一系列问题,只要去关心我们要实现的逻辑就行了。

好了,现在做一下简单的总结吧。

  • 1. Handler与哪个线程的Looper相关联,那么它的消息处理逻辑就在与之相关的线程中执行,相应的消息的走向也就在相关联的MessageQueue中。(最常见的就是Handler与主线程关联,那么接收Looper回传的消息后的逻辑就会在主线程中执行)
  • 2. 当主线程中需要与子线程进行通信时(比如将耗时操作放在子线程中),建议使用HandlerThread。同时要注意,千万不要去重写它的run方法。

二、一个主线程与子线程互相通信的例子

     知识点都说完了。下面我们来写一个具体的例子实践一下吧。新建一个项目,修改它的MainActivity代码,如下:

public class ThreadHandlerActivity extends Activity{private TextView tv;private Handler mHandler;//与子线程关联的Handlerprivate Handler handler;//与主线程关联的Handlerprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv = new TextView(this);tv.setText("Handler实验");setContentView(tv);//实例化一个特殊的线程HandlerThread,必须给其指定一个名字HandlerThread thread = new HandlerThread("handler thread");thread.start();//千万不要忘记开启这个线程//将mHandler与thread相关联mHandler = new Handler(thread.getLooper()){public void handleMessage(android.os.Message msg) {Log.d("我是子线程----->", Thread.currentThread()+"");handler.sendEmptyMessage(1);//发送消息给主线程};};handler = new Handler(){public void handleMessage(android.os.Message msg) {Log.d("我是主线程----->", Thread.currentThread()+"");mHandler.sendEmptyMessage(1);//发送消息给子线程};};mHandler.sendEmptyMessage(1);//发送消息handler.sendEmptyMessage(1);//发送消息}}

注释很详细,不解释 了。运行程序,结果如下:

         这样子,就会一直循环下去,轮流打印出主线程和子线程。

 

相关文章:

主线程与子线程之间相互通信(HandlerThread)

平时&#xff0c;我们一般都是在子线程中向主线程发送消息&#xff08;要在主线程更新UI&#xff09;&#xff0c;从而完成请求的处理。那么如果需要主线程来向子线程发送消息&#xff0c;希望子线程来完成什么任务。该怎么做&#xff1f;这就是这篇文章将要讨论的内容。 一、…...

13基于双层优化的电动汽车日前-实时两阶段市场竞标

MATLAB代码&#xff1a;基于双层优化的电动汽车日前-实时两阶段市场竞标 关键词&#xff1a;日前-实时市场竞标 电动汽车 双层优化 编程语言&#xff1a;MATLAB平台 参考文献&#xff1a;考虑电动汽车可调度潜力的充电站两阶段市场投标策略_詹祥澎 内容简介&#xff1a;…...

REDIS19_zipList压缩列表详解、快递列表 - QuickList、跳表 - SkipList

文章目录①. 压缩列表 - zipList②. 快递列表 - QuickList③. 跳表 - SkipList①. 压缩列表 - zipList ①. ZipList是一种特殊的"双端链表",由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作,并且该操作的时间复杂度为O(1) (oxff:11111111) type…...

JavaScript 基础 - 第3天

文章目录JavaScript 基础 - 第3天笔记数组数组的基本使用定义数组和数组单元数据单元值类型数组长度属性操作数组JavaScript 基础 - 第3天笔记 数组 数组的基本使用 定义数组和数组单元 <script>// 1. 语法&#xff0c;使用 [] 来定义一个空数组// 定义一个空数组let…...

23.3.26总结

康托展开 是一个全排列与自然数的映射关系&#xff0c;康托展开的实质是计算当前序列在所有从小到大的全排列中的顺序&#xff0c;跟其逆序数有关。 例如&#xff1a;对于 1,2,3,4,5 来说&#xff0c;它的康托展开值为 0*4&#xff01;0*3&#xff01;0*2&#xff01;0*1&…...

【Java学习笔记】37.Java 网络编程

Java 网络编程 网络编程是指编写运行在多个设备&#xff08;计算机&#xff09;的程序&#xff0c;这些设备都通过网络连接起来。 java.net 包中 J2SE 的 API 包含有类和接口&#xff0c;它们提供低层次的通信细节。你可以直接使用这些类和接口&#xff0c;来专注于解决问题&…...

Azure OpenAI 官方指南03|DALL-E 的图像生成功能与安全过滤机制

2021年1月&#xff0c;OpenAI 推出 DALL-E。这是 GPT 模型在图像生成方面的人工智能应用。其名称来源于著名画家、艺术家萨尔瓦多 • 达利&#xff08;Dal&#xff09;和机器人总动员&#xff08;Wall-E&#xff09;。DALL-E 图像生成器&#xff0c;能够直接根据文本描述生成多…...

【数据结构】堆

文章目录前言堆的概念及结构堆初始化堆的判空堆的销毁插入数据删除数据堆的数据个数获取堆顶数据用数组创建堆对数组堆排序有关topk问题整体代码展示写在最后前言 &#x1f6a9;前面了解了树&#xff08;-> 传送门 <-&#xff09;的概念后&#xff0c;本章带大家来实现一…...

电脑硬盘文件数据误删除/格式化为什么可以恢复? 怎么恢复?谈谈文件删除与恢复背后的原理

Hello 大家好&#xff0c; 我是元存储~ 主页&#xff1a;元存储的博客_CSDN博客 1. 硬盘数据丢失场景 我们在每天办公还是记录数据的时候&#xff0c;文件存储大多数都是通过硬盘进行存储的&#xff0c;因此&#xff0c;使用多了&#xff0c;各种问题就会出现&#xff0c;比如…...

Gateway服务网关

Spring Cloud Gateway为微服务架构提供一种简单有效的统一的 API 路由管理方式。Gateway网关是所有微服务的统一入口。网关的核心功能特性&#xff1a;请求路由和负载均衡&#xff1a;一切请求都必须先经过gateway&#xff0c;但网关不处理业务&#xff0c;而是根据某种规则&am…...

K8S + GitLab + Jenkins自动化发布项目实践(一)

K8S GitLab Jenkins自动化发布项目实践&#xff08;一&#xff09;发布流程设计安装Docker服务部署Harbor作为镜像仓库部署GitLab作为代码仓库常用Git命令发布流程设计 #mermaid-svg-pe9VmFytb9GmqMvG {font-family:"trebuchet ms",verdana,arial,sans-serif;font-…...

【数据结构篇C++实现】- 堆

文章目录&#x1f680;一、堆的原理精讲⛳&#xff08;一&#xff09;堆的概念⛳&#xff08;二&#xff09;看图识最大堆⛳&#xff08;三&#xff09;详解堆是用数组表示的树&#x1f680;二、堆的向下调整算法&#x1f680;三、堆的向上调整算法&#x1f680;四、将任意一棵…...

C++笔试题

作用域运算符(::)的作用&#xff1a;1.存在具有相同名称的局部变量时&#xff0c;访问全局变量。2.在类之外定义类相关函数。3.访问类的静态变量。4.在多重继承的情况下&#xff0c;如果两个基类中存在相同的变量名&#xff0c;可以使用作用域运算符来进行区分。5.限定成员函数…...

【Python】基本语法

数据类型 通过 print(type(x)) 可以输出 x 的数据类型&#xff0c;type() 函数可以获取数据类型 整数 a 10 print(type(a)) 浮点数 a 0.5 print(type(a)) 字符串 a hello print(type(a)) 获取字符串长度 a hello print(len(a))字符串拼接 a hello b world prin…...

用栈实现队列(图示超详解哦)

全文目录引言用栈实现队列题目介绍思路简述实现栈的部分队列的部分创建队列判断队列是否为空在队列尾入在队列头出访问队头元素释放队列总结引言 在上一篇文章中&#xff0c;我们了解了用两个队列实现栈。在这篇问章中将继续介绍用两个栈实现队列的OJ练习&#xff1a; 用栈实现…...

Spring - Spring 注解相关面试题总结

文章目录01. Spring 配置方式有几种&#xff1f;02. Spring 如何实现基于xml的配置方式&#xff1f;03. Spring 如何实现基于注解的配置&#xff1f;04. Spring 如何基于注解配置bean的作用范围&#xff1f;05. Spring Component, Controller, Repository, Service 注解有何区别…...

【数据结构】实现二叉树的基本操作

目录 1. 二叉树的基本操作 2. 具体实现 2.1 创建BinaryTree类以及简单创建一棵树 2.2 前序遍历 2.3 中序遍历 2.4 后序遍历 2.5 层序遍历 2.6 获取树中节点的个数 2.7 获取叶子节点的个数 2.8 获取第K层节点的个数 2.9 获取二叉树的高度 2.10 检测值为val的元素是否…...

代码随想录算法训练营第五十二天| ● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组

300.最长递增子序列 看完题后的思路 dp[i] [0,i]子数组中,以nums[i]结尾的子序列的长度 dp[i]dp[j]1 j从i-1向0遍历,在所有nums[j]<nums[i]中dp[j]最大 初始化 dp[0]1 代码 class Solution {public int lengthOfLIS(int[] nums) {if (nums.length0){return 0;}int[] dpne…...

手机验证发送及其验证(基于springboot+redis)保姆级

在Java开发中&#xff0c;发送手机验证码时需要考虑以下几个问题&#xff1a; 验证码的有效期&#xff1a;验证码应该有一定的有效期&#xff0c;一般设置为几分钟或者十几分钟。过期的验证码应该被认为是无效的&#xff0c;不能用于验证用户身份。手机号码格式的校验&#xf…...

【JavaScript 逆向】数美滑块逆向分析

声明本文章中所有内容仅供学习交流&#xff0c;相关链接做了脱敏处理&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01;案例目标验证码&#xff1a;aHR0cHM6Ly93d3cuaXNodW1laS5jb20vbmV3L3Byb2R1Y3QvdHcvY29kZQ以上均做了脱敏处理&#xff0c;Base64 编码及解码方…...

多任务之线程

文章目录一、多任务是什么&#xff1f;二、多任务-线程四、通过继承Tread类完成创建线程五、资源竞争六、同步与互斥锁七、对峙与避免死锁一、多任务是什么&#xff1f; 多个函数同时执行一件事情就是多任务&#xff0c;没有多任务的时候任务执行都是按照顺序的&#xff0c;而…...

(数字图像处理MATLAB+Python)第二章数字图像处理基础-第二节:色度学基础与颜色模型

文章目录一&#xff1a;颜色匹配二&#xff1a;CIE 1931-RGB系统三&#xff1a;CIE 1931标准色度系统四&#xff1a;CIE 1976Lab均匀颜色空间五&#xff1a;孟塞尔表色系统&#xff08;1&#xff09;孟塞尔明度(Value&#xff0c;记为V)&#xff08;2&#xff09;孟塞尔彩度(Ch…...

【华为OD机试 2023最新 】 网上商城优惠活动(C++)

文章目录 题目描述输入描述输出描述备注用例题目解析C++题目描述 某网上商场举办优惠活动,发布了满减、打折、无门槛3种优惠券,分别为: 每满100元优惠10元,无使用数限制,如100199元可以使用1张减10元,200299可使用2张减20元,以此类推;92折券,1次限使用1张,如100元,…...

记一次CentOS 8 部署packstack部署OpenStack失败案例,请直接看最后

首先你需要一台安装好CentOS8 的虚拟机&#xff0c;相关参数如图。两块网卡&#xff0c;网卡1 NAT IP 192.168.100.100 GW192.168.100.2 网卡2 可不做配置。能ping通百度。创建完成虚拟机记得打好快照。 开机编辑基本配置环境变量 [rootlocalhost ~]# nmcli connection show NA…...

【2023春招】美团技术岗笔试10min+AK

随手投递了前端&移动端,笔试2道算法+选择+行测题(为什么笔试会有行测题?) 目录 T1-火车栈结构 题意 输入描述 输出描述 样例 AC_Code T2-春游...

Echarts实现图表自适应屏幕分辨率

一&#xff1a;简介 之前做项目的时候要实现echarts图表随浏览器窗口大小变化而改变&#xff0c;echarts本身提供了一个resize()方法&#xff0c;然后我们需要用一个函数实现浏览器窗口监听&#xff0c;最初我选用的是window.onresize方法&#xff0c;当页面只有一个图表时可以…...

【2023年第十一届泰迪杯数据挖掘挑战赛】B题:产品订单的数据分析与需求预测 建模及python代码详解 问题一

相关链接 【2023年第十一届泰迪杯数据挖掘挑战赛】B题&#xff1a;产品订单的数据分析与需求预测 建模及python代码详解 问题一 【2023年第十一届泰迪杯数据挖掘挑战赛】B题&#xff1a;产品订单的数据分析与需求预测 建模及python代码详解 问题二 1 题目 一&#xff0e;问题…...

【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式国赛客观题以及详细题解

题1 概念题。 USRAT&#xff1a;异步串口通信&#xff0c;常用于数据传输&#xff1b;SW-DP&#xff1a;SWD 的全称应该是 The Serial Wire Debug Port (SW-DP),也就是串行调试端口&#xff0c;是 >ARM 目前支持的两种调试端口之一&#xff1b;JTAG-DP&#xff1a;另一个调试…...

java中Map遍历的4种方式

目录 1、map.entrySet()方式 2、map.keySet()方式 3、map.values()方式 4、forEach方式 本文以如下map案例&#xff1a; Map<String, String> map new HashMap<>(); map.put("student1", "张三"); map.put("student2", "…...

GCC 编译器的主要组件和编译过程

主要组件&#xff1a; 分析器&#xff1a;分析器将源语言程序代码转换为汇编语言。因为要从一种格式转换为另一种格式&#xff08;C到汇编&#xff09;&#xff0c;所以分析器需要知道目标机器的汇编语言。 汇编器&#xff1a;汇编器将汇编语言代码转换为CPU可以执行字节码。 …...

wordpress拼音/百度竞价推广效果好吗

C语言之类型转换 类型之间的转换 1.c语言中的数据类型可以进行转换 —强制类型转换 —隐式类型转换 //示例1 int main() {long l 800;int i (int)l; //强制类型转换return 0; }//示例2 int main() {short s 800;int i s; //隐式类型转换//no error,no warningreturn …...

国外扁平化网站/编写网页的软件

关于VIEW 登陆后 键盘无法输入的问题。主要因为使用了360防火墙的缘故&#xff01; PCOIP为VMware私有协议&#xff0c;不在360信任列表。使用RDP方式没有此问题。 解决方法有两种&#xff1a;1.打开360安全卫士&#xff0c;进入木马防火墙————关闭键盘记录防护 &#xff…...

怎样做txt电子书下载网站/什么软件可以弄排名

随着导航技术的发展&#xff0c;无人叉车可以自由运行&#xff0c;作业指导书和作业反馈信息是闭环的&#xff0c;信息流与实际物流通过与 mes、 wms 等的双向信息集成实现同步。通过 wms 远程调度任务&#xff0c;将智能调度系统的任务交给自主叉车的作业指令&#xff0c;协调…...

免费网站建设公司推荐/优化营商环境

author YHC 这个教程向你展示如何附加节点到tree,我们将创建一个食品tree包含水果和蔬菜节点,然后添加一些其他水果到已存在的水果节点. 创建 foods(食品) tree 首先,我们创建食品树,代码就像这样. <div style"width:200px;height:auto;border:1px solid #ccc;"&…...

湖北响应式网站建设企业/短网址生成器免费

&#x1f4d2; 博客首页&#xff1a;✎﹏ℳ๓敬坤的博客 &#x1f388; &#x1f60a; 我只是一个代码的搬运工 &#x1f383; &#x1f389; 欢迎来访的读者关注、点赞和收藏 &#x1f91e; &#x1f609; 有问题可以私信交流 &#x1f606; &#x1f4c3; 文章标题&#xff1…...

国外域名注册哪个网站好/重庆排名优化整站优化

展开全部您好&#xff0c;如果您经常被骚扰电话困32313133353236313431303231363533e4b893e5b19e31333335313166扰&#xff0c;可以尝试安装腾讯手机管家进行骚扰电话拦截与举报喔。管家除了可以拦截骚扰电话外&#xff0c;还可以拦截垃圾短信&#xff0c;将讨厌的号码设为黑名…...