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

devtools/2024/10/19 9:32:19/

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

目录

一、同步异步

二、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;
​@Overrideprotected 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() {@Overridepublic 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() {@Overridepublic void run() {if (i > 0){tv_aaa.setText(i--+"");handler1.postDelayed(this,1000);}else {handler1.removeCallbacksAndMessages(null);}}};
​
​
/*private void aaa() {
​handler.postDelayed(new Runnable() {@Overridepublic 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() {@Overridepublic 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.ppmy.cn/devtools/120491.html

相关文章

JavaScript for循环语句

for循环 循环语句用于重复执行某个操作,for语句就是循环命令,可以指定循环的起点、终点和终止条件。它的格式如下 for(初始化表达式;条件;迭代因子){语句} for语句后面的括号里面,有三个表达式 初始化表达式(initialize):确定循环变量的初始…

java 解析excel (本地资源)

在Java中解析Excel文件,可以使用Apache POI库。以下是一个简单的例子,展示如何使用Apache POI读取一个Excel文件(假设为.xlsx格式)的内容。 首先,确保你的项目中包含了Apache POI的依赖。如果你使用Maven,…

机器学习(6):机器学习项目步骤(三)——选择算法并建立模型

1. 选择算法 a. 数据集里的某些特征和标签之间,存在着近似线性的关系. b. 这个数据集的标签是连续变量 因此选择回归分析算法 c. 我们在上一讲的可视化过程中,推测特征和标签可能存在线性关系 因此选择线性回归算法 2. 选择算法工具包 我们一般选算法包的…

龙芯1B开发板自检程序

本代码为当时,参加嵌入式系统开发与应用赛项,训练时编写的自检程序,用于将程序烧录后,逐个演示板载模块功能是否正常,快速定位问题。这代码编写的时间为2023年,好像原代码是参考2023年官方案例来编写的。目…

python 实现rayleigh quotient瑞利商算法

rayleigh quotient瑞利商算法介绍 瑞利商(Rayleigh Quotient)算法在多个领域,如线性代数、计算机视觉和机器学习等,都有重要的应用。瑞利商定义为函数 R ( A , x ) ( x H A x ) / ( x H x ) R(A, x) (x^H Ax) / (x^H x) R(A,x)…

ESP32简介

文章目录 ESP32简介一、ESP32的核心特性**1. ** **CPU处理能力****2. ** **全面的无线通信支持****3. ** **丰富的外设接口****4. ** **低功耗设计****5. ** **易于开发与部署** 二、ESP32的应用场景 ESP32简介 在物联网(IoT)日益蓬勃发展的今天&#x…

Python编码系列—Python状态模式:轻松管理对象状态的变化

🌟🌟 欢迎来到我的技术小筑,一个专为技术探索者打造的交流空间。在这里,我们不仅分享代码的智慧,还探讨技术的深度与广度。无论您是资深开发者还是技术新手,这里都有一片属于您的天空。让我们在知识的海洋中…

21.2 k8s中etcd的tls双向认证原理解析

本节重点介绍 : tls单向认证原理tls双向认证原理 在k8s中etcd监控的应用以ca.crt client.crt client.key创建的secret并挂载到prometheus中prometheus配置证书信息打到采集etcd的目的 tls单向认证 在单向SSL身份认证过程中,客户端需要验证服务端证书,…