对于Handler是怎么进行线程通信,它的原理又是什么,你了解多少?

Android——Handler详解 1. 简介 Handler是一套 Android 消息传递机制 可以说只要有异步线程与主线程通信的地方就一定会有 Handler。 在多线程的应用场景中,将工作线程中需更新UI的操作信息 传递到 UI主线程,从而实现 工作线程对UI的更新处理,最终实现异步消息的处理 使用Handler消息传递机制主要是为了多个线程并发更新UI的同时,保证线程安全 2. 相关概念解释 Handler、Message、Message Queue、Looper Android消息机制: 以Handler的sendMes 阅读详情

题目:Handler怎么进行线程通信,原理是什么?

首先我们要知道这道题想考察什么?
  1. 是否熟悉Handler的基本用法
  2. 是否熟悉Handler消息机制的运行流程
  3. 是否明白Handler进行线程通信的原理
考察的知识点
  1. 利用Handler进行线程切换的基本流程
  2. Handler消息机制涉及到的类以及之间的关系
  3. Handler是怎样做到线程通信的
考生应该如何回答
  1. 先说一下Handler机制的运行流程,以及涉及到的类之间的关系

    Handler消息机制主要涉及到四个类:Handler、Looper、MessageQueue、Message.

    Handler: 字面意为处理器,负责消息的分发与处理,内部持有一个looper对象和一个MessageQueue对象(MessageQueue对象通过looper对象获得)

    Looper: 字面意为循环器,跑在特定的线程里面,持有一个MessageQueue对象,主要通过loop()方法循环地从MessageQueue中来拿到当前线程需要处理的消息并处理。我们通常意义上的切换线程,归根结底就是切换到了这个方法中。为什么需要loop()循环?通常我们开启一个新的线程,当代码执行完线程也就结束了,如果想要该线程做到不断接收并处理外部发来的消息,就需要开启looper。

    MessageQueue: 消息队列,也就是存放Message的地方,维护了一个通过时间优先级排列的单链表,Handler发出的消息会先存进此队列再被取出执行。

    Message: 消息,可携带参数及标识,并持有发送该消息的Handler对象。post(Runnable)方式最后也会被改为Message对象,并将Runnable赋值给Message的callback,处理消息时调用。

    一次完整的事件发送与处理流程为:Handler调用sendMessage/post方法,调用其持有的MessageQueue对象的enqueueMessage方法将消息添加到消息队列,looper通过loop()方法会不断的从该MessageQueue中取出Message,并调用Message持有的target(Handler)对象的dispatchMessage方法,进而执行到Handler的handlerMessage或者Runnable的run方法或者额外的callback进行处理。
  2. 说一下Handler怎么做到线程通信,其原理是什么

    我们在新建一个Handler的时候,在其构造方法中会给其持有的mLooper对象赋值,Handler通过mLooper实现与线程的绑定。

    mLooper对象可以在构造方法中传入,或者在构造方法中通过Looper.myLooper()方法获取。

    //Handler.java
    public Handler(@Nullable Callback callback, boolean async) {
        mLooper = Looper.myLooper();
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    
    //Looper.java
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) { //当前线程中已经有looper对象,抛出异常
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    

    可以看到looper对象是以ThreadLocal的形式存放的,也就是每个线程中都有自己单独的looper对象。

    线程中的looper对象在调用Looper.prepare()方法的时候进行初始化并赋值,并且通过判空的方式来保证一个线程中只有一个looper对象。

    需要说明的一下是,主线程中的looper是在应用程序进程创建的时候,在ActivityThread的main()方法中进行创建并开启循环的,不需要我们手动创建,而子线程中的looper是需要我们自己调用prepare()/loop()方法来初始化并开启循环。

    //ActivityThread.java
    public static final void main(String[] args) {
        //主线程, 进程启动时自动调用
        Looper.prepareMainLooper()
        //由这里的loop()方法处理的消息运行在主线程
        Looper.loop();
    }
    
    //XXActivity.java
    new Thread() {
        @Override
        public void run() {
            super.run();
            //子线程, 需手动调用
            Looper.prepare();
            //由这里的loop()方法处理的消息运行在子线程
            Looper.loop();
        }
    }.start();
    

    由此我们知道了Looper.loop()在哪个线程调用,其消息循环就执行在哪个线程中。

    而Looper.loop()中干了什么事?就是获取到当前线程的looper对象(怎么获取的?前面说了,ThreadLocal中获取),再拿到其内部MessageQueue对象,从其中不断地取出消息并执行,也就是我们线程代码实际运行的地方。既然loop()中执行的是MessageQueue中的消息,我们不难想到,若想让代码执行在这个某个线程中,肯定是要跟这个线程的MessageQueue发生关系的。

    //Handler.java
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue; //这里的mQueue即mLooper对象中的MessageQueue
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis); //将Message对象添加到MessageQueue队列中
    }
    
    //Looper.java (此处仅贴出关键代码)
    public static void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next();
            msg.target.dispatchMessage(msg);
            //dispatchMessage 会调用到handler的handleMessage方法或者Runnable的run方法
            //或者额外传入的Callback的handleMessage方法.
        }
    }
    

    可以看到,当(比如子线程中)调用Handler.sendMessage时,会将消息传入该Handler所绑定的mLooper的MessageQueue中,这一步是发送消息的过程。也就是说,消息会从一个线程被发送到另一个线程的消息队列。如果创建Handler时传入的是主线程的looper对象,那么主线程中的Looper.loop()函数就会从这个MessageQueue中取到子线程发来的这个消息并执行。怎么执行呢?就是调用message.target.dispatchMessage() -> handleMessage()方法,而这里的target就是发送该消息的handler。而由于Looper.loop()是在主线程,所以这条消息也就执行在了主线程中。

    所以Handler完成线程通信通俗点说原理就是:在A线程中获得绑定了B线程looper的handler的引用,用此handler发送的消息会进入B线程的消息队列,最终会跑在B线程的Looper.loop()方法中,这样就完成了从A线程到B线程的通信。

    这里要区分一下线程对象和线程的概念:线程对象就是Thread对象,是虚拟机中实实在在存在的,文章中所说的哪个线程的mLooper对象,MessageQueue对象都是指这个Thread对象所持有的对象;而线程是系统调度的单位,是一段代码的运行过程,通过Thread类的start()方法来真实启动的。所以一个线程中调用Looper.loop()方法,从本线程对象的MessageQueue中拿数据,而这个MessageQueue,其他线程也可以通过Handler往里面发送消息(这里需要加锁来保证线程安全),这样就完成了线程的通信。线程通信本质上是线程间对象或者说内存的共享。

    下面以一段代码来更清楚地演示一下从子线程向主线程发送消息以及从主线程向子线程发送消息的过程。

    public class MyActivity extends AppCompatActivity {
    
        //与主线程绑定的Handler, 此处主动传入looper对象, 与调用默认构造方法效果是一样的
        Handler mMainHandler = new MainThreadHandler(Looper.myLooper());
        //与子线程绑定的Handler, 需要在子线程中创建, 定义为全局变量以便在主线程中引用
        SubThreadHandler mSubHandler;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    mMainHandler.sendEmptyMessage(0);      //子线程发送消息给主线程
                    Looper.prepare();                      //子线程中需要手动初始化looper
                    mSubHandler = new SubThreadHandler();  //初始化子线程Handler
                    Looper.loop();                         //开启循环
                }
            }.start();
    
            //主线程发送消息给子线程, 这里延后1秒钟以保证mSubHandler完成初始化
            mMainHandler.postDelayed(() -> mSubHandler.sendEmptyMessage(1), 1000);
    
        }
    
        private static class MainThreadHandler extends Handler {
    
            public MainThreadHandler(Looper looper) {
                super(looper);
            }
    
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                //do work in main thread
                Log.d("HandlerTest", "MainThreadHandler: " + msg.what + ", current thread: " + Thread.currentThread().getName());
            }
        }
    
        private static class SubThreadHandler extends Handler {
    
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
                //do work in sub thread
                Log.d("HandlerTest", "SubThreadHandler: " + msg.what + ", current thread: " + Thread.currentThread().getName());
            }
        }
    }
    

    执行结果:

    10928-10928/com.xx.newtest D/HandlerTest: MainThreadHandler: 0, current thread: main
    10928-11722/com.xx.newtest D/HandlerTest: SubThreadHandler: 1, current thread: Thread-4

    首先得到的是子线程发送来的消息,执行在主线程;接着得到主线程发送来的消息,执行在子线程。

【Android】Handler之线程间通信 Android多线程之间的消息传递是通过Handler来实现的。不同的线程之间又分为两类:即Main Thread(主线程)和Worker Thread(”苦力“线程) 。 Main Thread又称为UI Thread,意思是主线程负责Android App的界面管理与显示和与用户之间的交互,是最重要的也是最核心的Thread,所以我们要对它细心呵护, 如果处理不当使UI Threa 阅读详情

相关推荐

通信之线程间通信(上)-handler

多线程的知识改天再总结,先介绍一下多线程之间的通信 只有主线程才能去更新UI线程,如果程序中开启了子线程,而又想去更新UI,这时候就要借助Handler将消息传给主线程,进行刷新UI,简单的总结一下handler的用法 1,在activity中创建handler,更新UI的操作在此进行: private Handler mHandler = new Handler(){ public v

fanfan 4512

Handler工作原理和处理线程间通讯

消息处理的五大组成部分: Message Handler Message Queue Looper ThreadLocal 1、Message数据模型,用于线程之间传递消息, 常用四个字段: target:消息回调的作用域类,通常是一个handler; what:区分不同消息得标识符; obj:是一个对象类型,可以携带自定义的类; arg:int类型携带参数; 2、hand...

u010498248的博客 446

android 子线程使用handler通信

我们日常使用处理线程间的通信是 主线程与子线程之间相互通信,也就是使用android提供的handler。 那么子线程之间如何相互通信呢?一般有可能会使用 全局变量来进行通信,其实我们也可以使用系统提供的handler来进行子线程中的通信。 handler的通信机制 此处引用:https://blog.youkuaiyun.com/blackzhangwei/article/details/5...

仰望星空的博客 3777

Handler通信机制

目标:1.Handler和Looper什么关系?2.一个线程有几个Handler?3.Handler内存泄漏的原因?4.使用Message时如何创建它?5.子线程维护的Looper, 消息队列无消息时的处理方案是怎么样的?有什么用?6.为什么主线程可以new Handler?如果想要在子线程new Handler,应该怎么办?7.线程间通信原理是怎么样的?8.Looper死循环为什么不会导致应用卡死?

joedan0104的专栏 884

终于明白了Handler怎么线程间通信的

一直对handler似懂非懂,这次看了别的文章加上自己的理解,终于明白Handler到底是如何实现线程间的通信了.大家共同探讨研究. 首先得明白,一个线程只有一个Looper和MessageQueue.调用本线程的Handler只能发送Message到本线程的MessageQueue.那怎么区分Handler是哪个线程的呢,是通过Handler对象中的Looper对象.然后本线程Looper对象loop(),不断从MessageQueue取消息。 1.主线程初始化Handler //内存泄漏的问题请先

鸿蒙开发知识记录 1872

这篇带你搞懂Handler怎么线程间通信的

一直对handler似懂非懂,这次看了别的文章加上自己的理解,终于明白Handler到底是如何实现线程间的通信了.大家共同探讨研究. 首先得明白,一个线程只有一个Looper和MessageQueue.调用本线程的Handler只能发送Message到本线程的MessageQueue.那怎么区分Handler是哪个线程的呢,是通过Handler对象中的Looper对象.然后本线程Looper对象loop(),不断从MessageQueue取消息. 1.主线程初始化Handler //内存泄漏的问题请先

鸿蒙开发知识记录 1448

为RTX 4080量身打造:在Ubuntu 20.04上一步到位配置CUDA 12.1 + cuDNN 8.9.5 + PyTorch 2.0环境

本文详细指导如何在Ubuntu 20.04上为RTX 4080显卡配置CUDA 12.1 + cuDNN 8.9.5 + PyTorch 2.0的深度学习环境,提供经过实测的黄金组合方案,确保发挥显卡最佳性能并保持系统稳定。

weixin_30887919的博客 517

Handler的底层原理实现

Handler相信大家对Handler再熟悉不过了,平常使用它的频率也比较高,我们知道它是用来线程间通信的,但是handler是怎么实现通信的,可能就需要我们做进一步的了解,在面试中也是经常会问到的问题,下面我就带着大家跟一跟Handler的源码。 在跟代码之前我们先对Handler原理做个大致打介绍: Handler:用来发送消息,处理消息 Message:消息实体对象,handler

itheimach的专栏 6676

Handler实现线程间通信的原理

本文以Handler对象的创建和消息发送为切入点,讲述背后的实现原理。

qiaoyanfei的专栏 3503

Android Handler机制(线程间通信)↑

在Android中,提供了异步消息处理机制的两种方式来解决线程之间的通信问题,一种是Handler机制,还有一种是AsyncTask机制。 1.handler 我们都知道,Android UI是线程不安全的,如果在子线程中尝试进行UI操作,程序就会崩溃。相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也是早已烂熟于心,即创建一个Message对象,然后借助Handler发送出去,之后在Handler的handleMessage()方法中获得刚才发送的Message对象,然后在这里进行UI操作就不

zenmela2011的专栏 2284

Handler机制的作用真的是线程间通信吗?

首先,线程之间本来就可以相互修改对象属性,因为对象存储在堆内存中,堆内存本来就是线程共享的。看下面这段代码的运行结果,就明白了。 public class HandlerTest { static class Message { String name; int age; } public static void main(String[] args) { Message msg = new Message(); .

知道这个有什么用? 300

Handler是怎么实现跨线程通信的

Handler的消息发送,和消息获取机制

qq_42426725的博客 1686

Handler线程通信机制:实战、原理、性能优化!

本文从实战、原理以及性能优化三个方面,详细且全面的介绍了Hander通信机制的使用、低层原理的实现,以及Handler内存泄漏的原因及解决方案的实现。

卜大爷的博客 2万+

Android的Handler机制实现线程间通信原理

Handler机制的核心原理是。

分享技术和日常 966

MoveIt2 Servo实战:解锁UR机械臂在ROS2中的实时遥操作与动态响应

本文深入探讨了MoveIt2 Servo在UR机械臂实时遥操作中的应用,展示了如何通过ROS2实现毫秒级动态响应。文章详细解析了Servo的核心价值、环境配置、控制器适配及高级调优技巧,特别适用于需要高精度控制的工业场景,如VR手术训练和汽车装配线。

weixin_29044157的博客 247

BurpSuite实战:5分钟搞定Pikachu靶场表单爆破(附最新字典配置技巧)

本文通过Pikachu靶场实战,详细演示了如何使用BurpSuite的Intruder模块对Web登录表单进行暴力破解。从代理配置、请求捕获、集束炸弹模式设置,到载荷配置与结果分析,提供了完整的操作流程。文中还分享了2024年有效的字典获取与优化技巧,帮助安全测试人员快速定位弱口令漏洞。

weixin_29327977的博客 600

【Android】使用Handler做多个线程之间的通信

Android中Handler的线程通信机制,分析了四种Handler使用场景:1)主线程Handler更新UI;2)子线程Handler不传Looper导致UI更新失败;3)子线程设置Looper实现消息处理;4)子线程使用主线程Looper更新UI。文章还解析了Looper.prepare()、Looper.myLooper()和Looper.loop()的核心作用,并通过示例演示了多线程通信和延迟消息发送的实现。关键点在于理解Handler与Looper的绑定关系,以及如何通过消息队列实现跨线程通信

阿华的博客 1264

别再只会用555了!手把手教你用运放和RC电路搭一个50Hz正弦波信号源(附Multisim仿真文件)

本文详细介绍了如何使用运放LM358和RC电路搭建一个精准的50Hz正弦波信号源,涵盖文氏电桥核心原理、单电源供电解决方案、Multisim仿真及实物调试技巧。通过实战指南和优化建议,帮助电子爱好者快速掌握低频信号生成技术,适用于各种测试和校准场景。

weixin_34116482的博客 364

Android使用Handler实现子线程与子线程、主线程之间通信

今天这篇文章只讲一下怎么使用Handler实现子线程与子线程之间、子线程与主线程之间如何进行通信,关于具体的内部实现因为我也没研究过,所以这篇文章讲不了。一、子线程向主线程传值:这个实现比较简单,因为主线程自带Looper机制,所有我们不用创建Looper了,看一下代码吧:首选在主线程里创建一个Handler1.Handler mHandler = new Handler(){ 2. 3.

shaoenxiao的博客 2万+

FPGA以太网通信实战(一):实现MDIO接口驱动,掌控PHY芯片的钥匙

本文介绍了以太网通信技术及其核心组件。首先概述了以太网的发展历程,从标准以太网(10Mbps)到万兆以太网(10Gbps)的技术演进。重点分析了以太网接口的两大核心部件:MAC控制器负责数据链路层协议处理,PHY芯片负责物理信号转换和连接管理。文章详细解读了MDIO接口规范,包括帧格式和读写时序,并以YT8531 PHY芯片为例,介绍了其寄存器配置方法。最后设计了一个FPGA实现方案,通过MDIO接口完成PHY芯片的软复位和状态监测功能,并利用LED指示灯实时显示网络连接速率。

weixin_64402689的博客 1661

研究生如何快速发CVPR

研究生如何快速发CVPR,找到科研方向

python_vb的博客 785

Android Handler 通信 - 彻底了解 Handler 的通信过程

相关文章链接: 1. Android Handler 通信 - 源码分析与手写 Handler 框架 2. Android Handler 通信 - 彻底了解 Native 层的通信过程 相关源码文件: /frameworks/base/core/java/android/os/Handler.java /frameworks/base/core/java/android/os/MessageQu...

z240336124的专栏 1008

STM32驱动HC-SR04超声波模块

本篇文章将带大家使用HAL库驱动HC-SR04超声波模块。超声波模块作为智能小车必备的模块,要学习智能小车的同学是必须掌握好这个模块的使用的。HC-SR04是一种常用的超声波传感器模块,也被称为超声波测距模块,广泛应用于各种自动化控制和测距系统中。它通常由超声波发射器、接收器、控制电路和外壳组成,可以实现非接触式的距离测量。下面是HC-SR04超声波模块的一些特性和技术参数:距离测量范围:2cm ~ 400cm(可调)。测量精度:0.3cm。工作电压:DC 5V。工作电流:15mA。

m0_49476241的博客 7684

Android 线程通信之handler机制

Handler机制主要为了解决以下2个问题 1). 不要阻塞UI线程; 2). 不要在UI线程之外访问UI组件,即不能在子线程访问UI组件,只能在UI线程访问。

m0_59162559的博客 1509

人工智能---什么是Transformer?

Transformer是一种强大的神经网络架构,最初由Google的研究人员在论文《Attention is All You Need》中提出,用于自然语言处理任务,特别是在机器翻译方面取得了巨大成功。Transformer的核心思想是完全基于自注意力机制(self-attention mechanism)来实现序列到序列(sequence-to-sequence)的学习。它在自然语言处理(NLP)和其他序列到序列任务中表现出色,逐渐成为该领域的主流模型。近些年也逐渐在自动驾驶领域有所应用。

智能汽车人的博客 3955

使用AutoDL云服务器训练YOLO计算机视觉网络模型(AutoDL+Xftp+VS Code),附详细操作步骤

AutoDL AI算力云是一个提供人工智能算力服务的云平台。丰富的GPU资源:提供多种GPU型号,包括NVIDIA的A100A800L40V100RTX 4090RTX 3090等,能满足我们在不同场景下的需求,无论是进行大规模的AI训练还是复杂的科学计算等任务,都可以找到合适的GPU资源。灵活的付费方式:支持按量付费包日包周包月等多种付费模式。对于短期的实验或不确定时长的项目,可以选择按量付费;如果有长期稳定的算力需求,预付费或包周包月则可能更划算,可以根据自己的需求和预算进行选择。集成主流框架:集成了。

Limiiiing的博客 957
上一篇: 前端性能优化的常用手段
下一篇: apk瘦身之旅,你了解多少
AndroidYingZi
博客等级 码龄6年 6粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值