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

news/2025/1/8 2:29:14/

目录

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.ppmy.cn/news/1561142.html

相关文章

web3基于OP_Rollup的L2扩容方案-Arbitrum

业务模型 价值&#xff1a;arbitrum对于用户来说的核心价值是交易速度、更低的gas费用、欺诈证明技术保证L2层交易具备L1层的安全性。 L2层的网络具备兼容L1层所有应用的特点&#xff0c;任何L1层的应用都可以拓展到L2层&#xff0c;包括普通的消息调用、治理、代币交易等。 …

node.js内置模块之---http 和 https 模块

http 和 https 模块的作用 在 Node.js 中&#xff0c;http 和 https 模块用于创建和处理 HTTP 和 HTTPS 请求/响应 http模块 http 模块提供了用于实现 HTTP 协议的功能。它可以用来创建 HTTP 服务器&#xff0c;处理 HTTP 请求&#xff0c;发送 HTTP 响应&#xff0c;同时也可以…

大象喝水C++

题目&#xff1a; 代码&#xff1a; #include<iostream> #include<cmath> using namespace std; int main(){double r,c,h,pi,v,water;pi3.14159;cin>>h>>r;vpi*r*r*h/1000.0;water20.0/v;cceil(water);cout<<c<<endl;return 0; }

MCS-51单片机常用汇编指令和特殊功能寄存器~

今天给小伙伴们总结了一下MCS-51单片机常用的汇编指令和特殊功能寄存器&#xff0c;希望能在大家解决问题时提供帮助~。 一.汇编指令 1.数据传输指令 MOV A, #data: 将立即数传送到累加器A。MOV A, Rn: 将寄存器Rn的内容传送到累加器A。MOV Rn, #data: 将立即数传送到寄存器…

springboot573学院个人信息管理系统(论文+源码)_kaic

摘 要 随着社会的发展&#xff0c;学院个人信息的管理形势越来越严峻。越来越多的用户利用互联网获得信息&#xff0c;但学院个人信息鱼龙混杂&#xff0c;信息真假难以辨别。为了方便用户更好的获得学院个人信息&#xff0c;因此&#xff0c;设计一种安全高效的学院个人信息管…

OneFlow的简单介绍

OneFlow 是北京一流科技有限公司旗下的采用全新架构设计的开源工业级通用深度学习框架。以下是关于 OneFlow 的详细介绍&#xff1a; 本篇文章的目录 特点 功能 应用场景 发展历程 特点 简洁易用的接口&#xff1a;为深度学习相关的算法工程师提供一套简洁易用的用户接口…

【Go研究】Go语言脚本化的可行性——yaegi项目体验

0x01 背景——云计算中脚本化困境 作为云基础设施管理中&#xff0c;大量需要跟文件系统、容器等相关的操作&#xff0c;这些操作实现通常用脚本来实现。 现在探讨下&#xff0c;这些脚本为什么一定要用脚本语言来实现&#xff0c;以及目前实现中的常见的问题。 常见的两个场…

计算机网络 (17)点对点协议PPP

一、PPP协议的基本概念 PPP协议最初设计是为两个对等节点之间的IP流量传输提供一种封装协议&#xff0c;它替代了原来非标准的第二层协议&#xff08;如SLIP&#xff09;。在TCP/IP协议集中&#xff0c;PPP是一种用来同步调制连接的数据链路层协议&#xff08;OSI模式中的第二层…