Handler详解系列——利用Handler在主线程与子线程之间互发消息,handler详解

2024-06-10 07:32

本文主要是介绍Handler详解系列——利用Handler在主线程与子线程之间互发消息,handler详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


MainActivity如下:

package cc.c;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.widget.TextView;
/*** Demo描述:* * 示例步骤如下:* 1 子线程给子线程本身发送消息* 2 收到1的消息后,子线程给主线程发送消息* 3 收到2的消息后,主线程给子线程发送消息* * 为实现子线程给自己本身发送消息,关键还是在于构造Handler时传入的Looper.* 在此就传入该子线程自己的Looper即调用Looper.myLooper(),代码如下:* Looper.prepare();* mHandlerTest1=new HandlerTest1(Looper.myLooper());* Looper.loop();* * 所以当mHandlerTest1.sendMessage(message);发送消息时* 当然是发送到了它自己的消息队列.* * 当子线程中收到自己发送的消息后,可继续发送消息到主线程.此时只要注意构造* Handler时传入的Handler是主线程的Handler即可,即getMainLooper().* 其余没啥可说的.* * * 在主线程处理消息后再发消息到子线程* * * 其实这些线程间发送消息,没有什么;关键还是在于构造Handler时传入谁的Looper.**/
public class MainActivity extends Activity {private TextView mTextView;private HandlerTest1 mHandlerTest1;private HandlerTest2 mHandlerTest2;private int counter=0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);init();}private void init() {mTextView = (TextView) findViewById(R.id.textView);//1 子线程发送消息给本身new Thread() {public void run() {Looper.prepare();mHandlerTest1=new HandlerTest1(Looper.myLooper());Message message = new Message();message.obj = "子线程发送的消息Hi~Hi";mHandlerTest1.sendMessage(message);Looper.loop();};}.start();}private class HandlerTest1 extends Handler {private HandlerTest1(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);System.out.println("子线程收到:" + msg.obj);//2  收到消息后可再发消息到主线程mHandlerTest2=new HandlerTest2(getMainLooper());Message message = new Message();message.obj = "O(∩_∩)O";mHandlerTest2.sendMessage(message);}}private class HandlerTest2 extends Handler {private HandlerTest2(Looper looper) {super(looper);}@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);mTextView.setText("在主线程中,收到子线程发来消息:" + msg.obj);//3  收到消息后再发消息到子线程if (counter==0) {Message message = new Message();message.obj = "主线程发送的消息Xi~Xi";mHandlerTest1.sendMessage(message);counter++;}}}}

main.xml如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/hello_world"android:layout_centerInParent="true"android:layout_marginTop="70dip" /></RelativeLayout>




对于Android Handler与Message的多线程消息的处理,为什我以下代码会死掉? 看看,

1.线程没有终止条件,会一直给主线程发消息,主线程不停的调用handleMessage代码,很容易ANR(应用程序不响应)
2.handler.obtainMessage()得到message对象比new Message();更高效
 

Android Handler机制 怎使用?

Handler对象与其调用者在同一线程中,如果在Handler中设置了延时操作,则调用线程也会堵塞。每个Handler对象都会绑定一个Looper对象,每个Looper对象对应一个消息队列(MessageQueue)。如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。
在主线程中,可以直接使用new Handler()创建Handler对象,其将自动与主线程的Looper对象绑定;在非主线程中直接这样创建Handler则会报错,因为Android系统默认情况下非主线程中没有开启Looper,而Handler对象必须绑定Looper对象。这种情况下,需先在该线程中手动开启Looper(Looper.prepare()-->Looper.loop()),然后将其绑定到Handler对象上;或者通过Looper.getMainLooper(),获得主线程的Looper,将其绑定到此Handler对象上。
Handler发送的消息都会加入到Looper的MessageQueue中。一说Handler包含两个队列:线程队列和消息队列;使用Handler.post()可以将线程对象加入到线程队列中;使用Handler.sendMessage()可以将消息对象加入到消息队列中。通过源码分析证实,Handler只有一个消息队列,即MessageQueue。通过post()传进去的线程对象将会被封装成消息对象后传入MessageQueue。
使用post()将线程对象放到消息队列中后,当Looper轮询到该线程执行时,实际上并不会单独开启一个新线程,而仍然在当前Looper绑定的线程中执行,Handler只是调用了该线程对象的run()而已。如,在子线程中定义了更新UI的指令,若直接开启将该线程执行,则会报错;而通过post()将其加入到主线程的Looper中并执行,就可以实现UI的更新。
使用sendMessage()将消息对象加入到消息队列后,当Looper轮询到该消息时,就会调用Handler的handleMessage()来对其进行处理。再以更新UI为例,使用这种方法的话,就先将主线程的Looper绑定在Handler对象上,重载handleMessage()来处理UI更新,然后向其发送消息就可以了。

这篇关于Handler详解系列——利用Handler在主线程与子线程之间互发消息,handler详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1047532

相关文章

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

Go路由注册方法详解

《Go路由注册方法详解》Go语言中,http.NewServeMux()和http.HandleFunc()是两种不同的路由注册方式,前者创建独立的ServeMux实例,适合模块化和分层路由,灵活性高... 目录Go路由注册方法1. 路由注册的方式2. 路由器的独立性3. 灵活性4. 启动服务器的方式5.

Java中八大包装类举例详解(通俗易懂)

《Java中八大包装类举例详解(通俗易懂)》:本文主要介绍Java中的包装类,包括它们的作用、特点、用途以及如何进行装箱和拆箱,包装类还提供了许多实用方法,如转换、获取基本类型值、比较和类型检测,... 目录一、包装类(Wrapper Class)1、简要介绍2、包装类特点3、包装类用途二、装箱和拆箱1、装