深入Android架构(从线程到AIDL)_11 线程之间的通信架构

目录

5、 线程之间的通信架构

认识Looper与Handler对象

主线程丢信息给自己

子线程丢信息给主线程

替子线程诞生Looper与MQ


5、 线程之间的通信架构

认识Looper与Handler对象
  • 当主线程诞生时,就会去执行一个代码循环(Looper),以便持续监视它的信息队列(Message Queue简称MQ)。当UI事件发生了,通常会立即丢一个信息(Message)到MQ,此时主线程就立即从MQ里面取出该信息,并且处理之。
  • 例如,用户在UI画面上按下一个Button按钮时, UI事件发生了,就会丢一些信息到MQ里,其中包括onClick信息,于是,主线程会及时从MQ里取出onClick信息,然后调用Activity的onClick()函数去处理之。处理完毕之后,主线程又返回去继续执行信息循环,继续监视它的MQ,一直循环下去,直到主线程的生命周期的终了。
  • 通常是进程被删除时,主线程才会被删除
  • Android里有一个Looper类别,其对象里含有一个信息循环(Message Loop)。也就是说,一个主线程有它自己专属的Looper对象,此线程诞生时,就会执行此对象里的信息循环。此外,一个主线程还会有其专属的MQ信息结构。如下图所示:
  • 由于主线程会持续监视MQ的动态,所以在程序的任何函数,只要将信息(以Message类别的对象表示之)丢入主线程的MQ里,就能与主线程沟通了。
  • 在Android里,也定义了一个Handler类别,在程序的任何函数里,可以诞生Handler对象来将Message对象丢入MQ里,而与主线程进行沟通。
  • 在Android的预设情况下,主线程诞生时,就会拥有自己的Looper对象和MQ(即Message Queue)数据结构
  • 然而,主线程诞生子线程时,于预设情形下,子线程并不具有自己的Looper对象和MQ。由于没有Looper对象,就没有信息回圈(Message Loop),一旦工作完毕了,此子线程就结束了。
  • 既然没有Looper对象也没有MQ,也就不能接受外来的Message对象了。则别的线程就无法透过MQ来传递信息给它了。
  • 那么,如果别的线程(如主线程)需要与子线程通讯时,该如何呢? 答案是:替它诞生一个Looper对象和一个MQ就行了。
主线程丢信息给自己
  • Handler是Android框架所提供的基类,用来协助将信息丢到线程的MQ里。
  • 兹撰写个范例程序Rx01,来将信息丢到主线程的MQ里,如下:
// ac01.java
//……..
public class ac01 extends Activity implements OnClickListener {private Handler h;public void onCreate(Bundle icicle) {//……..h = new Handler(){public void handleMessage(Message msg) {setTitle((String)msg.obj);}}; 
}public void onClick(View v) {switch (v.getId()) {case 101:h.removeMessages(0);Message m = h.obtainMessage(1, 1, 1, "this is my message.");h.sendMessage(m); // 将Message送入MQ里break;case 102: finish(); break;
}}}
  • 当主线程执行到onCreate()函数里的指令:

         h = new Handler(){
            // ………
         }

  • 就诞生一个Handler对象,可透过它来把信息丢到MQ里。
  • 当执行到onClick()函数里的指令:
    //………………
    h.removeMessages(0);
    Message m = h.obtainMessage(1, 1, 1,"this is my message.");
    h.sendMessage(m);
  • 就将Message对象送入MQ里。
  • 当主线程返回到信息回圈时,看到MQ里有个Message对象,就取出来,并执行handleMessage()函数,将Message对象里所含的字符串显示于画面上。
子线程丢信息给主线程
  • 子线程也可以诞生Handler对象来将Message对象丢到主线程的MQ里,又能与主线程通讯了。兹撰写个范例程序Rx02如下:

 

// ac01.java
// ……….
public class ac01 extends Activity implements OnClickListener {private Handler h;private Timer timer = new Timer();private int k=0;public void onCreate(Bundle icicle) {super.onCreate(icicle);//………h = new Handler(){public void handleMessage(Message msg) {setTitle((String)msg.obj);}};}public void onClick(View v) {switch (v.getId()) {case 101:TimerTask task = new TimerTask(){@Override public void run() {h.removeMessages(0);Message m = h.obtainMessage(1, 1, 1,Thread.currentThread().getName() + " :"+String.valueOf(k++));h.sendMessage(m);}};timer.schedule(task, 500, 1500); break;case 102:finish(); break;}}
}
  • 就启动一个Timer的线程,名字叫:” Timer-0” ;然后,由它来定时重复执行TimerTask::run()函数,就不断将Message对象丢到主线程的MQ里。此时主线程会持续处理MQ里的Message对象,将其内的字符串显示于画面上。

       

  • 于是,子执行透过Handler对象而将信息丢到主线程的MQ,进而成功地将信息显示于画面上。
     
替子线程诞生Looper与MQ
  • 如果别的线程(如主线程)需要与子线程通讯时,该如何呢? 答案是:替它诞生一个Looper对象和一个MQ就行了。兹撰写个范例程序Rx03如下:
    // ac01.java
    //……
    public class ac01 extends Activity implements OnClickListener {private Thread t;private Handler h;private String str;public void onCreate(Bundle icicle) {//……..t = new Thread(new Task());t.start(); }public void onClick(View v) {switch(v.getId()){case 101:Message m = h.obtainMessage(1, 33, 1, null);h.sendMessage(m); break;case 102: setTitle(str); break;case 103: h.getLooper().quit(); finish(); break;}}class Task implements Runnable {public void run() {Looper.prepare();h = new Handler(){public void handleMessage(Message msg) {str = Thread.currentThread().getName() +", value=" +                String.valueOf(msg.arg1);}};Looper.loop();}}
    }

  • Step-1: 一开始,由主线程执行onCreate()函数。 主线程继续执行到指令:
        t = new Thread(new Task());
        t.start();

  • 就诞生一个子线程,并启动子线程去执行Task的run()函数,而主线程则返回到信息回圈,并持续监视MQ的动态了。

  • Step-2: 此时,子线程执行到run()函数里的指令:
         Looper.prepare();

  • 就诞生一个Looper对象,准备好一个信息回圈(Message Loop) 和MQ数据结构

  • 继续执行到指令:
         h = new Handler(){
               //…..
          }

  • 就诞生一个Handler对象,可协助将信息丢到子线程的MQ上。

  • 接着继续执行到指令:
           Looper.loop();

  • 也就开始执行信息回圈,并持续监视子线程的MQ动态了。

  • Step-3: 当用户按下UI按钮时, UI事件发生了, Android将此UI事件的信息丢到主线程的MQ,主线程就执行onClick()函数里的指令:
           Message m = h.obtainMessage(1, 33, 1, null);
           h.sendMessage(m);

  • 主线程藉由h将该Message对象(内含整数值33)丢入子线程的MQ里面,然后主线程返回到它的信息循环(Looper),等待UI画面的事件或信息。

  • Step-4: 子线程看到MQ有了信息,就会取出来,调用handleMessage()函数:
           public void handleMessage(Message msg) {
                  str = Thread.currentThread().getName() +", value=" + String.valueOf(msg.arg1);
           }

  • 来处理之,就设定的str的值。请留意,此刻子线程因为不能碰触UI控件,所以无法直接将str值显示于画面上。

  • Step-5: 当用户按下<show value>按钮时,主线程就执行onClick()函数,将str值显示于画面上。 于是,实现主线程与子线程之间的双向沟通了。
     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/66266.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【中间件】docker+kafka单节点部署---zookeeper模式

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言消息中间件介绍1. KRaft模式2. zookeeper模式2.1. 单节点部署安装验证 前言 最近生产环境上准备部署ELFK日志监控&#xff0c;先在测试环境部署单节点kafka验证…

AI-Talk开发板之超拟人

一、说明 运行duomotai_ap sdk下的LLM_chat例程&#xff0c;实现开发板和超拟人大模型进行语音交互&#xff0c;支持单轮和多轮交互。 二、SDK更新 v2.3.0及以上的SDK版本才支持超拟人&#xff0c;如果当前SDK在v2.3.o以下&#xff0c;需要更新SDK。在SDK目录(duomotai_ap)下…

2024年, Milvus 社区的那些事

随着跨年钟声响起&#xff0c;2024 年告一段落。这一年&#xff0c;Milvus GitHub Stars 正式突破 3 万大关&#xff0c;Docker 下载量突破6700w 次&#xff0c;达到一个新的里程碑&#xff0c;在开源向量数据库领域继续引领前行。在这遥遥领先的数据背后&#xff0c;不妨让我们…

docker中使用Volume完成数据共享

情景概述 在一个docker中&#xff0c;部署两个MySQL容器&#xff0c;假如它们的数据都存储在自己容器内部的data目录中。这样的存储方式会有以下问题&#xff1a; 1.无法保证两个MySQL容器中的数据同步。 2.容器删除后&#xff0c;数据就会丢失。 基于以上问题&#xff0c;容…

【期末复习】二、进程管理

1.进程的内存结构🍊 程序加载到内存之后就变成了一个进程,进程在内存当中的一个结构有: 文本段(text section):存放程序代码 栈(stack):存放局部变量和函数返回地址 数据段(data section):存放全局变量和静态变量(static) 堆(heap):程序运行时的动态内存分…

Type-C多口适配器:高效充电与连接解决方案

在科技飞速发展的今天&#xff0c;我们的生活已经离不开各种各样的电子设备&#xff0c;如智能手机、平板电脑、智能手表和无线耳机等。这些设备不仅丰富了我们的数字生活&#xff0c;也带来了更多的充电需求。传统的单一充电口已经难以满足现代人对于便捷性和效率的追求&#…

UCAS 24秋网络认证技术 CH10 SSL 复习

TLS字段、参数含义要了解每个消息是什么意思 基本方式只验证服务端&#xff0c;服务端有证书&#xff0c;变形方式加上验证客户端TLS1.3区别 协商过程 背景 Record层使用的各种加密算法参数&#xff0c;均由Handshake协议协商获得。 具体过程 随机数交换 Client/Server相互…

支付宝商家转账到账户余额,支持多商户管理

大家好&#xff0c;我是小悟 转账到支付宝账户是一种通过 API 完成单笔转账的功能&#xff0c;支付宝商家可以向其他支付宝账户进行单笔转账。 商家只需输入另一个正确的支付宝账号&#xff0c;即可将资金从本企业支付宝账户转账至另一个支付宝账户。 该产品适用行业较广&am…

基于Django的旅游信息管理系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决生活上的问题&#xff0c;线上管理系统展现了其蓬勃生命力和广阔的前景。与此同时&#xff0c;随着…

常见的框架漏洞复现

1.Thinkphp Thinkphp5x远程命令执行及getshell 搭建靶场 cd vulhub/thinkphp/5-rce docker-compose up -d 首页 漏洞根本源于 thinkphp/library/think/Request.php 中method方法可以进行变量覆盖&#xff0c;通过覆盖类的核心属性filter导致rce&#xff0c;其攻击点较为多&…

UE5中实现右键开镜效果

右键之后添加时间轴&#xff0c;然后设置视野即可。Set Field Of View 时间轴设置&#xff0c;第一个点设置0,90度&#xff0c;因为默认的就是90度 第二个点看武器的类型或者倍境来设置&#xff0c;时间就是开镜时间&#xff0c;值越小开镜速度越快&#xff0c;第二个值就是视野…

关于华硕Armoury Crate(奥创中心)安装程序失败、卡进度条问题解决方案

关于华硕Armoury Crate(奥创中心&#xff09;安装失败解决方案 清理旧版本文件 如果之前安装过Armoury Crate&#xff0c;可能有残留文件导致冲突&#xff1a; 利用官方的卸载工具&#xff0c;卸载旧版本&#xff1a; https://www.asus.com.cn/supportonly/armoury%20crate/…

iOS18 上的 Genmoji

在 WWDC 2025 期间&#xff0c;一种名为Genmoji的新型表情符号问世。 许多用户可能仍然不确定 Genmoji 是什么、它与传统表情符号有何不同、如何使用它以及如何恢复丢失的数据。因此&#xff0c;在本文中&#xff0c;我们将介绍您需要了解的有关 iOS 18 上的 Genmoji 的所有信…

基于等保的安全审计运维系统

摘要 本文研究与设计一种基于等级保护&#xff08;等保&#xff09;要求的安全审计运维系统&#xff0c;以适应日益严峻的网络安全形势和不断提高的安全审计需求。随着信息技术的快速发展和应用广泛&#xff0c;信息系统安全面临的威胁也在不断增加&#xff0c;特别是在关键信…

【OAuth2系列】如何使用OAuth 2.0实现安全授权?详解四种授权方式

作者&#xff1a;后端小肥肠 &#x1f347; 我写过的文章中的相关代码放到了gitee&#xff0c;地址&#xff1a;xfc-fdw-cloud: 公共解决方案 &#x1f34a; 有疑问可私信或评论区联系我。 &#x1f951; 创作不易未经允许严禁转载。 姊妹篇&#xff1a; 【OAuth2系列】集成微…

传感器与检测技术基础知识

传感器检测系统 检测系统的组成:传感器、信号调理、数握采集、信号处理、信号显示、信号输出、输入设备、稳压电源。 检测系统的基本误差分类&#xff1a;绝对误差、相对误差、引用误差&#xff0c;最大引用误差。 测量系统的误差分类&#xff1a;系统误差、随机误差、粗大误…

决定系数(R²分数)——评估回归模型性能的一个指标

目录 1.定义 2.计算举例 3. 结果分析 1.定义 R&#xff08;R平方&#xff09;分数&#xff0c;也称为决定系数&#xff0c;是用来评估回归模型性能的一个指标。它表示自变量解释因变量变异性的比例。R分数的取值范围通常在0到1之间&#xff0c;其值越接近1&#xff0c;说明…

stm32HAL库使LED闪烁

PC13引脚为开漏接法 生成代码时设置为out put open drain gpio out put level 设置为high 1表示熄灭 我们将pa9引脚连接为推挽接法 生成代码时设置为 out put push pull Gpio out put level 设置为low 0 表示熄灭 代码使其亮起再延时0.5秒再熄灭再延时0.5秒

矩阵运算提速——玩转opencv::Mat

介绍:用Eigen或opencv::Mat进行矩阵的运算&#xff0c;比用cpp的vector或vector进行矩阵运算要快吗? 使用 Eigen 或 OpenCV 的 cv::Mat 进行矩阵运算通常比使用 std::vector<int> 或 std::vector<double> 更快。这主要有以下几个原因&#xff1a; 优化的底层实现…

yolo小damo合集

效果如下&#xff1a;这个是图片检测 效果如下&#xff1a;这个是视频检测 效果如下&#xff1a;这个是摄像头检测 1 相关库 除了yolov11所用库之外&#xff0c;本文所用到的额外库为pyqt5&#xff0c;输入指令进行安装 pip install pyqt5 导入所需要的库 import sys fro…