Android-Handle消息传递和线程通信

本文为作者学习笔记,如有误,请各位大佬指点

目录

一、同步异步

二、Java多线程通信

三、Handler是什么

四、Handler相关的类

五、Handler常用方法

1. 发送消息

2. 接收处理消息

3. 切换线程

六、使用Handler

使用Handler更新UI

使用Handler延时更新UI

使用Handler消息传递

使用Handler消息延迟传递

Handler移除功能

Handler消息拦截

七、Handler原理

八、线程、looper、messageQueue、Handler的数量级关系

九、Handler案例-倒计时


一、同步异步

同步:一个进程在执行某个请求时,如果该请求需要一段时间才能返回信息,那么这个进程会一直等待下去,直到收到返回信息才继续执行下去。

异步:异步是指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有信息返回的时候会通知进程进行处理,这样就可以提高执行的效率了,

并发:多个任务在同一个时间段进行,在同一时刻,其实只有一个任务在进行。即在一台处理器上“同时”(同时间段)处理多个任务。

并行:多个任务在同一时刻发生,把每一个任务分配给每一个处理器独立完成。在同一时刻,任务一定是同时运行。并行在多台处理器上分别同时处理多个任务。

二、Java多线程通信

Java 中有很多种方法实现线程之间相互通信访问数据,比如:

  • 通过 synchronized 关键字以“上锁”机制实现线程间的通信。多个线程持 有同一个对象,他们可以访问同一个共享变量,利用 synchronized“上锁” 机制,哪个线程拿到了锁,它就可以对共享变量进行修改,从而实现了通信。

  • 使用 Object 类的 wait/notify 机制,执行代码 obj.wait();后这个对象 obj 所在的线程进入阻塞状态,直到其他线程调用了 obj.notify();方法 后线程才会被唤醒。

三、Handler是什么

  • 更新UI

    当后台任务完成时,通过handler将结果发送到UI线程,以更新UI界面,比如显示加载完成的数据、更新进度条等。

  • 实现消息传递和线程通信的

    Android应用通常会涉及到多个线程的并发执行,通过Handler,在不同线程间发送消息和处理消息,实现线程间的通信,比如主线程和后台线程之间的通信。

  • 解决多线程并发

    假设如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,就会产生更新界面错乱。

    如果对更新UI的操作都进行加锁处理又会使应用性能下降,

    所以Android给我们提供了handler,只需要遵循这样的机制就可以了,根本不用去关心多线程问题,都是在主线程的消息队列当中去轮询处理的。

  • 定时任务处理

    可以使用Handler的postDelayed()方法来延迟执行代码块或发送延时消息。

    这对于实现定时刷新、定时执行任务等场景非常有用。

四、Handler相关的类

Handler:发送和接收消息

Looper:轮询消息队列,一个线程只能有一个Looper

Message:消息实体

MessageQueue:消息队列 用于存储消息和管理消息

五、Handler常用方法

1. 发送消息

  • boolean sendMessage (Message msg)

    发送一条消息

  • boolean sendMessageDelayed (Message msg, long sendMessageDelayed )

    在过了 delayMillis 毫秒之后发送一条消息。

  • boolean sendMessageAtTime (Message msg, long uptimeMillis)

    在具体指定的时间 uptimeMillis 发送一条消息。uptimeMillis 为系统开机到当 前的时间(毫秒)。

  • boolean sendEmptyMessage (int what)

    发送一个只有消息标识 waht 的空消息。该方法适用于不需要传递具体消息只是 单独的发通知时。

    boolean sendEmptyMessageDelayed (int what, long delayMillis)

    在过了 delayMillis 毫秒之后发送一个只有消息标识 waht 的空消息。

  • boolean sendEmptyMessageAtTime (int what, long uptimeMillis)

    在具体指定的时间 uptimeMillis 发送一个只有消息标识 waht 的空消息。 uptimeMillis 为系统开机到当前的时间(毫秒)

2. 接收处理消息

  • void handleMessage (Message msg)

    处理消息的方法。该方法通常用于被重写。

  • final boolean hasMessages(int what)

    检查消息队列中是否包含what属性为指定值的消息。

  • final boolean hasMessages(int what, Object object)

    检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息。

  • 多个重载的Message obtainMessage()

    获取消息。

3. 切换线程

  • boolean post (Runnable r)

    Runnabler会运行在 handler 对象被创建的线程上。当我们在 UI 线程创建了 Handler 对象,在 Worker 线程调用 handler.post()方法时,Runnable 就会运行 在 UI 线程中。

  • boolean postAtTime (Runnable r, long uptimeMillis)

    在具体指定的时间 uptimeMillis 让 Runnable 运行在 Handler对象被创建的线程 中。

  • boolean postDelayed(Runnable r, long delayMillis)

    在具体指定的时间 delayMillis 之后让 Runnable 运行在 Handler 对象被创建的 线程中

六、使用Handler

使用Handler更新UI

  • 定义handler

    privite Handler handler = new Handler();
  • 定义runnable

    Runnable runnable = new Runnable(){
        public void run(){
            textView.setText("cx")
        }
    };
  • 启动runable

    handler.post(runnable);

使用Handler延时更新UI

  • 定义handler

  • 定义runnable

  • 启动runable

    handler.postDelayed(runnable,2000);//延时2秒更新UI
  • 发送延时通知

    handler.sendEmptyMessageDelayed(what,2000);

使用Handler消息传递

  • 创建消息(可以创建不同类型的消息)

    //Message mes = handler.obtainMessage()
    Messagae mes = new Message();
    mes.arg1=66;
    mes.arg1=32;
    mes.obj="djka";
    //发送消息
    //或者mes.sendToTargrt();
    handler.sendMessage(mes);
  • 接收并处理消息

    privite Handler handler = new Handler(){
        public void handlerMessage(Message message){
            textViw.setText( (String)message.obj + message.arg1 +  message.arg2);
        }
    };

使用Handler消息延迟传递

  • 创建消息(可以创建不同类型的消息)

    handler.sendMessageDelayed(mes);
  • 接收并处理消息

Handler移除功能

比如在延时更新UI过程中移除,只是UI不再显示,

handle.removeCallbacks(runnable);

Handler消息拦截

  • 消息接收

    private Handler handler = new Handler(new Callback() {
        public boolean handleMessage(Message msg) {
            Toast.makeText(getApplicationContext(), "1", 1).show();
            return true;//返回false,执行完上面的代码在执行下面的;返回true,则不再执行下面的代码
        }
        
    }){
        public void handleMessage(Message msg) {
            Toast.makeText(getApplicationContext(), "2", 1).show();
        }
    };
  • 发送一个空消息

    handler.sendEmptyMessage(1);

七、Handler原理

  • Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息传给handler自己,MessageQueue就是一个存储消息的容器。

    • Handler

      是消息处理器,负责接收和处理消息。

      每个Handler实例都关联一个特定的线程,并与该线程的消息队列关联。

      可以发送和处理消息,实现线程间的通信。

    • Message

      Handler传递的消息对象,用于在不同线程之间传递数据。

      包含要传递的数据和附加消息(消息类型、标志等)。

      通过Handler的sendMessage()方法发送到目标线程的消息队列中,并在目标线程中被处理

    • Looper

      消息循环器,用于管理线程的消息队列。

      每个线程只能有一个Looper对象,负责不断地读取队列中的消息,并将消息通过Handler的dispatchMessage()传递给对用的Handler进行处理。

  • Handler工作原理

    • 当一个线程需要使用Handler来处理消息时,首先创建一个Looper对象:

      在ActivityThread中的main方法中,系统调用Looper.prepareMainLooper(),调用其prepare()创建一个与当前线程关联的消息队列。

      prepare(boolean quitAllowed) quitAllowed的作用是在创建MessageQueue时,标识消息队列是 否可以销毁, 主线程不可被销毁

    • 通过Looper的loop()启动消息循环,读取消息队列中的消息。

    • 当有消息通过Handler的sendMessage()发送到消息队列时,Looper会不断从消息队列中读取消息,并传递给对用的Handler进行处理。

    • Handler接收到消息后,调用自己的handleMessage()来处理消息。

Handler消息处理流程

message中callback是一个Runnable对象,如果callback不为空,则直接调用callback的 run方法,

否则判断mCallback是否为空,mCallback在Handler构造方法中初始化,在主线程通直接通过无参的构造方法new出来的为 null,所以会直接执行后面的handleMessage()方法。

public void dispatchMessage(Message msg) {
    //callback在message的构造方法中初始化或者使用handler.post(Runnable)时候才不为空
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        //mCallback是一个Callback对象,通过无参的构造方法创建出来的handler,该属性为null,此段不执行
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);//最终执行handleMessage方法
    }
}
private static void handleCallback(Message message) {
    message.callback.run();
}

八、线程、looper、messageQueue、Handler的数量级关系

一个 Thread 只能有一个 Looper,一个 MessageQueen,可以有多个 Handler 以一个线程为基准,他们的数量级关系是: Thread(1) : Looper(1) : MessageQueue(1) : Handler(N)

九、Handler案例-倒计时

public class MainActivity extends AppCompatActivity {
    private TextView tv_aaa;
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_aaa = findViewById(R.id.tv_aaa);
        //aaa();
        handler1.postDelayed(runnable,1000);
    }
​
/*    private Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            //tv_aaa.setText(msg.obj.toString());
        }
    };*/
​
    private int i=10;
​
    private Handler handler1=new Handler();
​
    private Runnable runnable=new Runnable() {
        @Override
        public void run() {
           if (i > 0){
               tv_aaa.setText(i--+"");
               handler1.postDelayed(this,1000);
           }else {
               handler1.removeCallbacksAndMessages(null);
           }
        }
    };
​
​
/*
    private void aaa() {
​
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                for (int i = 10; i > 0; i--) {
                    Log.d("xx", "run: ");
                    Message message = new Message();
                    //message.what = 0;
                    message.obj = i;
                    handler.sendMessageDelayed(message, (10-i) * 1000);
                }
            }
        }, 1000);
​
*/
/*
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 10; i > 0; i--) {
                            Log.d("xxz", "run: ");
                            Message message = new Message();
                            message.what = 0;
                            message.obj = i;
                            handler.sendMessageDelayed(message, 1000);
                        }
​
                    }
                }
        ).start();*//*
​
    }
*/
​
    //Handler handler = new Handler(){
    //    @Override
    //    public void handleMessage(@NonNull Message msg) {
    //        super.handleMessage(msg);
    //        switch (msg.what){
    //            case 0:
    //                tv_aaa.setText(msg.obj+"");
    //        }
    //    }
    //};
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

electron教程(三)窗口设置

在main.js文件中,创建窗口时会设置窗口的大小,其实还有很多其他属性,可以根据实际需求选择设置,但部分属性存在局限性,官网也有明确告知:自定义窗口 | Electron (electronjs.org) 项目文件目录如下&#x…

Windows安装Vim,并在PowerShell中直接使用vim

大家好啊,我是豆小匠。 这期介绍下怎么在windows的PowerShell上使用vim,方便在命令行里修改配置文件等。 先上效果图: 1、下载Vim GitHub传送门:https://github.com/vim/vim-win32-installer/releases 选择win-64的版本下载即可&…

信息技术网络安全政策制定

为什么要制定网络安全政策? 通常,公司并不认为需要制定网络安全政策。现有的政策是为了保护公司的资产,而数据也是一项资产。 网络安全政策的真正必要性很简单:网络安全并不像锁门或不偷公司笔那么简单。在许多情况下&#xff0…

HTML的修饰(CSS) -- 第三课

文章目录 前言一、CSS是什么?二、使用方式1. 基本语法2. 引入方式1.行内式2.内嵌式3. 链入式 3. 选择器1. 标签选择器2.类选择器3. id选择器4. 通配符选择器 4. css属性1. 文本样式属性2. 文本外观属性 5. 元素类型及其转换1. 元素的类型2. 元素的转换 6.css高级特性…

【Java的SPI机制】Java SPI机制:实现灵活的服务扩展

在Java开发中,SPI(Service Provider Interface,服务提供者接口)机制是一种重要的设计模式,它允许在运行时动态地插入或更换组件实现,从而实现框架或库的扩展点。本文将深入浅出地介绍Java SPI机制&#xff…

08_OpenCV文字图片绘制

import cv2 import numpy as npimg cv2.imread(image0.jpg,1) font cv2.FONT_HERSHEY_SIMPLEXcv2.rectangle(img,(500,400),(200,100),(0,255,0),20) # 1 dst 2 文字内容 3 坐标 4 5 字体大小 6 color 7 粗细 8 line type cv2.putText(img,flower,(200,50),font,1,(0,0,250)…

【AI学习】Mamba学习(二):线性注意力

上一篇《Mamba学习(一):总体架构》提到,Transformer 模型的主要缺点是:自注意力机制的计算量会随着上下文长度的增加呈平方级增长。所以,许多次二次时间架构(指一个函数或算法的增长速度小于二次…

国外电商系统开发-运维系统批量添加服务器

您可以把您准备的txt文件,安装要求的格式,复制粘贴到里面就可以了。注意格式! 如果是“#” 开头的,则表示注释!

【Qt】控件概述 (1)—— Widget属性

控件概述 1. QWidget核心属性1.1核心属性概述1.2 enable1.3 geometry——窗口坐标1.4 window frame的影响1.4 windowTitle——窗口标题1.5 windowIcon——窗口图标1.6 windowOpacity——透明度设置1.7 cursor——光标设置1.8 font——字体设置1.9 toolTip——鼠标悬停提示设置1…

《安富莱嵌入式周报》第343期:雷电USB4开源示波器正式发布,卓越的模拟前端低噪便携示波器,自带100W电源的便携智能烙铁,NASA航空航天锂电池设计

周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新一期视频教程 【授人以渔】CMSIS-RTOS V2封装层专题视频,一期视频将常用配置和用法梳理清楚&#xff0…

鸿蒙harmonyos next flutter通信之MethodChannel获取设备信息

本文将通过MethodChannel获取设备信息,以此来演练MethodChannel用法。 建立channel flutter代码: MethodChannel methodChannel MethodChannel("com.xmg.test"); ohos代码: private channel: MethodChannel | null nullthis.c…

openpnp - 图像传送方向要在高级校正之前设置好

文章目录 openpnp - 图像传送方向要在高级校正之前设置好笔记END openpnp - 图像传送方向要在高级校正之前设置好 笔记 图像传送方向和JOG面板的移动控制和实际设备的顶部摄像头/底部摄像头要一致,这样才能和贴板子时的实际操作方向对应起来。 设备标定完&#xf…

加油站智能视频监控预警系统(AI识别烟火打电话抽烟) Python 和 OpenCV 库

加油站作为存储和销售易燃易爆油品的场所,是重大危险源之一,随着科技的不断发展,智能视频监控预警系统在加油站的安全保障方面发挥着日益关键的作用,尤其是其中基于AI的烟火识别、抽烟识别和打电话识别功能,以及其独特…

V2M2引擎源码BlueCodePXL源码完整版

V2M2引擎源码BlueCodePXL源码完整版 链接: https://pan.baidu.com/s/1ifcTHAxcbD2CyY7gDWRVzQ?pwdmt4g 提取码: mt4g 参考资料:BlueCodePXL源码完整版_1234FCOM专注游戏工具及源码例子分享

[Cocoa]_[初级]_[绘制文本如何设置断行效果]

场景 在开发Cocoa程序时,表格NSTableView是经常使用的控件。其基于View Base的视图单元格模式就是使用NSCell或其子类来控制每个单元格的呈现。当一个单元格里的文字过多时,需要截断超出宽度的文字,怎么实现? 说明 Cocoa下的文本…

[Go语言快速上手]函数和包

目录 一、Go中的函数 函数声明 多个返回值 可变参数 匿名函数 值传递和地址传递 函数执行顺序(init函数) 二、Go中的包 基本语法 主要包(main package) 导入其他包 包的作用域 包的使用 包名别名 小结 一、Go中的函…

[C++]使用纯opencv部署yolov11目标检测onnx模型

yolov11官方框架:https://github.com/ultralytics/ultralytics 【算法介绍】 在C中使用纯OpenCV部署YOLOv11进行目标检测是一项具有挑战性的任务,因为YOLOv11通常是用PyTorch等深度学习框架实现的,而OpenCV本身并不直接支持加载和运行PyTor…

使用python基于DeepLabv3实现对图片进行语义分割

DeepLabv3 介绍 DeepLabv3 是一种先进的语义分割模型,由 Google Research 团队提出。它在 DeepLab 系列模型的基础上进行了改进,旨在提高图像中像素级分类的准确性。以下是 DeepLabv3 的详细介绍: 概述DeepLabv3 是 DeepLab 系列中的第三代…

设计模式-策略模式-200

优点:用来消除 if-else、switch 等多重判断的代码,消除 if-else、switch 多重判断 可以有效应对代码的复杂性。 缺点:会增加类的数量,有的时候没必要为了消除几个if-else而增加很多类,尤其是那些类型又长又臭的 原始代…

基于vue框架的大学生四六级学习网站设计与实现i8o8z(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能:学生,训练听力,学习单词,单词分类,阅读文章,文章类型,学习课程 开题报告内容 基于Vue框架的大学生四六级学习网站设计与实现开题报告 一、研究背景与意义 随着全球化进程的加速和国际交流的日益频繁,英语作为国际通用语言…