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

news2024/11/20 14:38:47

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

目录

一、同步异步

二、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+"");
    //        }
    //    }
    //};
}

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

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

相关文章

【MAUI】CommunityToolkit社区工具包介绍

一、为什么需要声明式开发 .NET的MVVM,始于WPF,很古典,它甚至可能是现代前端框架“声明式开发”的鼻祖。声明式开发,之所以出现,是因为命令式开发在UI层和代码层上无法解耦的问题。如下图所示: 1、命令式开发:后台代码需要调用UI层的控件(label.Text),如果更新UI层…

植物病虫害检测数据集 7800张 病虫害 带标注 voc yolo 7类

植物病虫害检测数据集 7800张 病虫害 带标注 voc yolo label| pic_ num| box_ num 越橘: . (932,980) 粘虫: (1104, 1104) 稻苞虫: (1389, 2269) 蝗虫: (1198, 1563) 蝽象若虫: (1594, 2576) . 绿蝽象: (1166&#xf…

微服务nginx解析部署使用全流程

目录 1、nginx介绍 1、简介 2、反向代理 3、负载均衡 2、安装nginx 1、下载nginx 2、解压nginx安装包 3、安装nginx​编辑 1、执行configure命令 2、执行make命令 4、启动nginx 1、查找nginx位置并启动 2、常用命令 3、反向代理 1、介绍反向代理配置 1、基础配置…

渗透测试入门学习——编写python脚本实现对网站登录页面的暴力破解

进入靶场输入任意密码进行尝试 发现登陆失败的特征字:“Username and/or password incorrect” 推荐用谷歌浏览器,按F12继续查看请求地址、请求头参数等详细信息,着重关注是否需要Cookie 编写python脚本 import requests # 填入请求地址 u…

Pikachu-csrf-CSRF(POST)

发起请求 拦截抓包&#xff0c;在请求信息中&#xff0c; Engagement Tool --》generate CSRF PoC 得到以下 html 代码 &#xff0c;生成poc.html 文件&#xff0c;当用户点击 <html><!-- CSRF PoC - generated by Burp Suite Professional --><body><…

C++仿函数的介绍以及priority_queue的介绍和模拟实现

目录 1.仿函数 1.1仿函数的介绍 1.2自定义类型使用仿函数 1.3自定义支持比较大小&#xff0c;但是比较的逻辑不是自己想要的逻辑 2.优先级队列priority_queue 2.1priority_queue的介绍 2.2priority_queue的使用 2.3priority_queue的模拟实现 1.仿函数 1.1仿函数的介绍…

Redis中一些其他的数据类型渐进式遍历

我们之前说了redis中的五个类型 分别是&#xff1a;String List Hash Set ZSet&#xff0c;那除了这五个redis文档中还给我们提供了一些其他的数据类型 &#xff08;一&#xff09;一些其他的数据类型 1.stream 这里的数据类型我们只做简单的一些介绍&#xff0c;如果想了解具体…

C++ | Leetcode C++题解之第452题用最少数量的箭引爆气球

题目&#xff1a; 题解&#xff1a; class Solution { public:int findMinArrowShots(vector<vector<int>>& points) {if (points.empty()) {return 0;}sort(points.begin(), points.end(), [](const vector<int>& u, const vector<int>&…

[云] Hands-on with a sample application--DockerCoins 挖矿程序!

DockerCoins 挖矿程序&#xff01;&#x1f4b0;&#x1f433;&#x1f4e6;&#x1f6a2; 不&#xff0c;你不能用 DockerCoins 买咖啡。 DockerCoins 如何工作&#xff1a; 生成一些随机字节&#xff1a; 程序首先生成一串随机的字节数据。这些随机字节用于模拟挖矿过程中的…

Pytorch实现玉米基因表达量预测模型

一、实验要求 通过搭建残差卷积网络&#xff0c;实现对玉米基因表达量的预测 二、实验目的 理解基因表达量预测问题&#xff1a;基因表达预测是生物信息学和基因组学领域中的重要任务之一&#xff0c;促进学科交叉融合。熟悉深度学习框架PyTorch&#xff1a;通过实现基因表达量…

Golang | Leetcode Golang题解之第453题最小操作次数使数组元素相等

题目&#xff1a; 题解&#xff1a; func minMoves(nums []int) (ans int) {min : nums[0]for _, num : range nums[1:] {if num < min {min num}}for _, num : range nums {ans num - min}return }

nodejs --- 使用全球公认头像gravatar

目录 历史&#xff1a;阿凡达 什么是头像&#xff1f; 我为什么要添加 Gravatar&#xff1f; 我怎样才能得到一个Gravatar&#xff1f; 开发者使用 功能描述 安装和使用 实践应用 我们他们名字旁边的灰色图标是怎么出现的。那么这个灰色图标被称为“神秘人”gravatar。…

IT新秀系列:Go语言的兴起

Go语言&#xff08;Golang&#xff09;由谷歌于2007年发起&#xff0c;并于2009年正式开源。它的诞生背景可以追溯到互联网技术的高速发展时期。那时&#xff0c;软件开发面临着多核计算、大规模并发处理、部署和维护效率低下等挑战。作为一种新型的编程语言&#xff0c;Go主要…

Nginx基础详解5(nginx集群、四七层的负载均衡、Jmeter工具的使用、实验验证集群的性能与单节点的性能)

续Nginx基础详解4&#xff08;location模块、nginx跨域问题的解决、nginx防盗链的设计原理及应用、nginx模块化解剖&#xff09;-CSDN博客 目录 14.nginx集群&#xff08;前传&#xff09; 14.1如何理解单节点和集群的概念 14.2单节点和集群的比较 14.3Nginx中的负载均衡…

指纹定位的原理与应用场景

目录 原理 1. 信号特征收集 2. 定位算法 推导公式 距离估算公式 定位算法公式 使用场景 发展前景 指纹定位是一种基于无线信号强度(如Wi-Fi、RFID、蓝牙等)来实现室内定位的技术。它借助于环境中多个基站的信号特征来推断用户的位置。以下是对指纹定位的详细讲解,包…

Spring Boot技术交流平台的设计与实践

3 系统分析 3.1 可行性分析 为了研究问题并确定问题是否能够在最短的时间内以最低的成本解决&#xff0c;经过对该项目的详细调查研究&#xff0c;初步准备了系统的实施报告&#xff0c;面临的问题和解决方案在软件开发方面进行了初步设计和合理安排&#xff0c;确定了开发目标…

Geoserver关于忘记密码的解决方法

第一次安装后&#xff0c;如果你设置密码那一栏一直都是默认的话&#xff0c;那么登录密码应该是账户 admin&#xff0c;密码 geoserver 但是&#xff0c;如果你自己设置了密码和账户&#xff0c;登录又登录不上&#xff0c;或者忘记了&#xff0c;有以下方法可以解决。 本质…

Hive数仓操作(九)

一、Hive的DQL查询顺序 HQL语法基本上与传统的SQL一致&#xff0c;包括SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY和LIMIT等关键步骤 SELECT * -- 1. 选择所有列 FROM employees -- 2. 数据来源是 employees 表 WHERE salary > 3000 -- 3. 筛选工资大于 3000 的…

AI在医学领域:Arges框架在溃疡性结肠炎上的应用

溃疡性结肠炎&#xff08;UC&#xff09;是一种慢性炎症性肠病&#xff08;IBD&#xff09;&#xff0c;在全球大约影响着500万人&#xff0c;导致肠道炎症和溃疡。在UC的临床试验中&#xff0c;通常通过内窥镜视频来评估结肠疾病的严重程度&#xff0c;并使用如Mayo内窥镜下分…

leetcode_198_打家劫舍

思路&#xff1a;首先定义一个数组对于dp[i]读作1->i能获取的最大利益&#xff0c;第i个房屋只有"偷"和不"偷"两种情况&#xff0c;分别进行讨论 "偷": 既然"偷"了 i那就肯定不能偷i-1了,但是为了使"偷"的尽可能多除了必…