Android消息机制浅析

【Android 】零基础到飞升 | Handler消息传递机制浅析 3.3 Handler消息传递机制浅析 分类 Android 基础入门教程 本节引言 前两节中我们对Android中的两种事件处理机制进行了学习,关于响应的事件响应就这两种;本节给大家讲解的 是Activity中UI组件中的信息传递Handler,相信很多朋友都知道,Android为了线程安全,并不允许我们在UI线程外操作UI;很多时候我们做界面刷新都需要通过Handler来通知UI组件更新!除了用Handler完成界面更新外,还可以使用runO... 阅读详情
private Handler handler=new Handler(){
    public void handleMessage(Message msg){
        //...
    }
}

new Thread(new Runnable(){
    public void run(){
        //...
        //...
        //...
        handler.sendMessage(msg);
    }
}).start();

上述代码是子线程更新UI界面常用的步骤,现在就来看看从new Handler开始,到handler.sendMessage之后都经历了哪些过程。

new Handler():

public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
        //获得当前线程的Looper     
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
            //这句话可以看出,在线程中创建handler的时候必须先调用Looper.prepare()
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //从looper中获取消息队列
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

来看上述代码我的三处注释

//获得当前线程的Looper     
mLooper = Looper.myLooper();

来看一下myLooper的源码:

/**
* Return the Looper object associated with the current thread.  Returns
* null if the calling thread is not associated with a Looper.
*/
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

解释下ThreadLocal,它不是一个线程,而是一个线程内部数据存储类,当某些数据是以线程为作用域并且不同线程具有不同副本的时候就可以用到这个。
Android中通过ThreadLocal将Looper保存到各自的线程中,于是,每个线程就有了各自的Looper中的MessageQueue。

//从looper中获取消息队列
mQueue = mLooper.mQueue;

拿到当前线程的Looper中就从looper中拿到MessageQueue。
那么这个mQueue是什么时候被创建的呢?进到Looper源码中:

    public static void prepare() {
        prepare(true);
    }
    //这个是主线程Looper的创建,平时用的handler都是创建在主线程中的
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
        //注意一下,每个线程只能有一个Looper,也就只有一个MessageQueue
        throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
    //Looper的构造函数
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

从源码可以看到,mQueue是在实例化Looper的时候被创建的,Looper的构造函数又是在prepare的时候调用的。

sendMessage(msg):

一路追踪,各种sendMessage最终都会调用以下函数:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
    MessageQueue queue = mQueue;
    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);
}

这里我进不了enqueueMessage(queue, msg, uptimeMillis)看源码,看书上解释的是MessageQueue的插入操作,虽然是叫MessageQueue,但它的实现不是队列,而是一个单链表。

到这里就完成了handler.sendMessage。

接下来就是接受和处理Message了。

Looper捕获Message:

public static void loop() {
    //前面的省略,直接看重点...
    //无线循环,唯一退出条件是queue返回null
   for (;;) {
    //从MessageQueue中获取Message
     Message msg = queue.next(); 
     if (msg == null) {
     // No message indicates that the message queue is quitting.
          return;
     }

     // This must be in a local variable, in case a UI event sets the logger
     Printer logging = me.mLogging;
     if (logging != null) {
         logging.println(">>>>> Dispatching to " + msg.target + " " +
         sg.callback + ": " + msg.what);
     }
     //这个target就是Handler,这里调用方法让Handler处理消息
     msg.target.dispatchMessage(msg);
   }
}

在主线程当中,这个loop()是会在ActivityThread中被调用:

public static void main(String[] args) {  
        ....  
        Looper.prepareMainLooper();  

        ActivityThread thread = new ActivityThread();  
        thread.attach(false);  

        if (sMainThreadHandler == null) {  
            sMainThreadHandler = thread.getHandler();  
        }  

        AsyncTask.init();  

        Looper.loop();  

        throw new RuntimeException("Main thread loop unexpectedly exited");  
    }  

Handler处理Message:

 public void dispatchMessage(Message msg) {
         //首先检查Message的callback是否为null
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            //其次检查Handler的callback是否为null
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //如果前两者都为null,执行handleMessage(),由handler子类实现
            handleMessage(msg);
        }
    }
     /**
     * Handler子类必须实现的方法
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    }

有个地方没注意:

Message next() {
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    //这里注意,没有Message是不返回null的!
                    nextPollTimeoutMillis = -1;
                }

                // 如果到了这里还没有返回,那说明没有Message了,检查下MessageQueue是否要退出,如果是,返回null,同时结束Looper.looper()的无限for循环
                if (mQuitting) {
                    dispose();
                    return null;
                }
     }
Cadence Virtuoso里搞定斩波运放AC仿真:PSS+PAC保姆级设置避坑指南 然而,当工程师们尝试在Cadence Virtuoso环境中对这种特殊结构进行AC特性分析时,往往会遇到传统AC仿真方法失效的困境——这正是PSS(Periodic Steady-State)与PAC(Periodic AC)仿真组合大显身手的场景。实际项目中我们常采用"先快后精"的两步法:先用快速设置确认大体趋势,再针对关键频段进行精细仿真。例如某次设计迭代中,将harmonics从10增加到20后,发现在1MHz处的相位裕度估算误差达15°,这解释了之前样机测试时的振荡问题。 阅读详情

相关推荐

从理论到波形:NE555多谐振荡器设计与示波器实战验证

本文详细介绍了NE555多谐振荡器的设计原理与实战验证方法。从基础理论到电路参数计算,再到面包板搭建与示波器测量,全面解析如何利用NE555芯片实现稳定的方波输出。通过实际案例演示了频率调整、占空比优化等技巧,并提供了常见问题排查指南,帮助电子爱好者快速掌握这一经典电路设计。

weixin_29159613的博客 280

浅析Android中的消息机制

Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。 前面提到,Android的消息队列和消息循环都是针对具体线程的,一个线程可以存在一个消息队列和消息循环,特定线程的消息只能分发给本线程,不能跨线程和跨进程通讯。但是创建的工作线程默认是没有消息队列和消息循环的,如果想让工作线程具有消息队列和消息循环,就需要在线程中先调用Loop

LiuHe 6万+

用V E S C 6-M K V I 第六代调速控制器给VESC电调刷固件

文章摘要:本文介绍了一款先进的电机控制器,具备多项创新技术。核心亮点包括三相电流/电压检测、四象限无缝运行、多模式兼容等先进电机控制技术,以及智能感知与安全保护、高效能电源管理、多样化连接与扩展功能。此外,该控制器支持实时数据监测与用户交互,具备开源生态和工业级可靠性,适用于电动载具、机器人及工业领域。用户需注意散热要求和兼容性提示,可通过VESC-Tool软件进行灵活配置。产品可在常竹科技淘宝店购买,并加入技术交流群获取支持。

2403_89422757的博客 1364

android中消息机制,深入浅析Android中的消息机制

深入浅析Android中的消息机制发布时间:2020-11-21 15:28:33来源:亿速云阅读:86作者:Leah本篇文章给大家分享的是有关深入浅析Android中的消息机制,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、简介Android的消息机制主要是指Handler的运行机制,那么什么是Handler的运行机制那?通俗的来...

weixin_39883260的博客 222

AMD MI50 Linux ROCm 6.4 手动编译与大模型推理实战

GPU加速计算是现代AI推理的核心基础,其性能依赖于硬件架构、驱动栈与运行时环境的深度协同。ROCm作为AMD开源GPU计算平台,采用‘自下而上’的Linux生态集成路径,强调对上游内核、编译器与固件的强耦合。MI50基于Vega 20(gfx900)架构,虽具备32GB HBM2高带宽显存与14.7 TFLOPS FP16算力,但因ROCm官方支持策略转向CDNA架构,自6.5版本起被移出支持列表,仅ROCm 6.4仍提供实验性兼容——这使其成为Linux下部署私有大模型的关键‘最后一班船’。本文围绕MI

weixin_32770423的博客 368

基于matlab的心电信号预处理

这是前段时间做的一个课程设计,做的比较简单,没有考虑到太细,只是初步地达到了想要的效果。这次设计主要是对心电信号进行预处理,将其信号中包含的一些干扰滤除或者抑制掉。 一、心电信号 (1)心电信号的特性   人体心电信号是非常微弱的生理低频电信号,通常最大的幅值不超过5mV,信号频率在0.05~100Hz之间。心电信号是通过安装在人体皮肤表面的电极来拾取的。由于电极和皮肤组织之间会发生极化现象

i_weimoli的博客 6万+

Android消息传递机制浅析

1.Looper、Handler、MessageQueue的关系 Looper 用于线程的消息循环,一个线程只能有一个Looper对象 Handler 执行任务调度和发生一些操作(在未来某时刻) 执行其他线程中的队列消息 MessageQueue 消息队列 一个Looper对应一个MessageQueue,并不断从MessageQueue中取出消息,提交给Handel处理。 2.Looper以主

_StriveG的专栏 3026

偷懒必备:3种方法快速移植MFC界面资源(含.rc文件打不开解决方案)

本文针对MFC桌面应用开发,详细介绍了三种快速移植界面资源的实战方法:直接编辑.rc文件、利用Visual Studio“添加现有项”进行可视化挂载,以及双实例拖拽应急方案。文章重点剖析了.rc文件无法打开的常见问题,提供了通过修复rc.exe等关键文件来根治此问题的解决方案,帮助开发者高效复用资源,规避ID冲突等陷阱。

weixin_28358083的博客 272

Android消息机制浅析——面试总结

前面两篇我们介绍了Android消息机制的使用以及分析了流程,这篇也是最后一篇,我们就播播面试题吧! 系列地址: Android消息机制浅析——基本使用 Android消息机制浅析——原理探究 Android消息机制浅析——面试总结面试题 如何将一个Thread线程变成Looper线程?Looper线程有哪些特点? 简述下Handler、Message、Looper、MessageQueue

钝悟需要时间的打磨,顿悟需要时间的积累 2400

CLAHE 算法学习 matlab

概念可参考: CLAHE (Contrast Limited Adaptive Histogram Equalization)算法学习CLAHE具体实现主要包括6个步骤。1):分块。将输入图像划分为大小相等的不重叠子块,每个子块含有的像素数为M。参考示例为8×8块。 2):计算子块直方图。 3):计算剪切阈值clipLimit 4):像素点重分配。对每个子块,使用步骤三中多余的像素重新分配。 5):直方图均衡。 6):像素点灰度值重构。(源码中采用了双线性插值) http://www.realtimer

baidu_34971492的博客 4253

单反相机物镜设计[DG-10]

REAR(要打在像面,操作数要找像面对应位置15):以透镜单位表示的真实光线径向坐标,波长由Wave定义,参见“Hx、Hy、Px和Py”。最小玻璃厚度最小不能小于semi-dia的1/10,要根据layout看有没有过厚过薄,反复调节。PROD:两个操作数的乘积(操作#1 X操作#2)。3x4就是57.3x0.41=23.5。拦光一般在第一面和最后一面操作,减少边缘无用光线。光阑面与镜面贴近,要调距离,同时设置光阑像差。后截距是指从镜头后表面到焦点的距离。CONS:弧度转为角度。镜头相互嵌入,有错误。

weixin_72050316的博客 600

浅析 Android 消息机制

浅析 Android 消息机制

jhope的专栏 764

ABAP CURR Data Type 深度解析与实战案例

CURR 数据类型是 SAP ABAP 中为处理货币金额而设计的一种特殊数据类型。CURR 数据类型能够自动根据关联的货币代码字段(例如 WAERS)确定小数位数,从而保证金额数据的精度与正确性。CURR 类型通常在 SAP 数据字典中使用,常见于各类业务数据表中,如会计凭证、销售订单等场景中,用于存储货币金额。CURR 数据类型底层实现上类似于 DEC 数据类型,但其特别之处在于与货币代码字段的绑定,这使得金额的格式化和显示可以自动匹配相应的货币规则。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 877

android 消息机制浅析

android消息机制主要涉及到以下内容:Message, Looper,Handler。 其原理为:消息线程(默认是主线程,也就是UI线程),维护一个消息循环和一个消息队列, 工作线程向消息队列中添加消息,消息循环从队列中取出消息并处理。其中Looper类负责消息循环 和消息队列,Message类是消息的载体,Handler类负责消息队列中添加消息和消息的处理。 Looper的prepa

海纳百川,壁立千仞 1385

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Android 消息机制-Handler浅析

Android的消息机制其实主要值得就是Handler的运行机制。 Handler的运行需要底层MessageQueue和Looper支撑。

longge33445的博客 408

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Android-消息机制(Handler机制)浅析

Android-消息机制浅析 简介 Android消息机制主要就是指Handler的运行机制; 借用网络的图片 图解: 1.以Handler的sendMessage方法为例,当发送一个消息后,会将此消息加入消息队列MessageQueue中。 2.Looper负责去遍历消息队列并且将队列中的消息分发给对应的Handler进行处理。 3.在Handler的handleMessage方法中处理该消息,这就完成了一个消息的发送和处理过程。 这里从图中可以看到参与消息处理有四个对象,它们分别是 Handler,

weixin_43506260的博客 475

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

浅析Android Handler消息机制的实现原理

0. 背景描述 Android系统出于对简单、高效的考虑,在设计UI体系时采用了单线程模型,即不会在多个线程中对同一个UI界面执行操作。简单是指单线程模型可以不用考虑和处理在多线程环境下操作UI带来的线程安全问题,高效是指单线程模型下无需通过额外的手段处理多线程安全问题(一般通过加锁等方式解决线程安全问题,而使用锁进行同步就会存在性能开销)。同时,因为Android应用属于UI交互型应用,需要对用户的操作进行快速响应,因此在处理UI操作的线程中不能执行网络请求、本地IO等这一类耗时操作,否则会导致用户的操作

boker_han的博客 1328

Android Handler 消息机制原理浅析

UI 线程、Message、MessageQueue、Handler、Looper、Handler 进行

麦客的Blog 251

Android消息机制浅析——原理探究

Android消息机制浅析——原理探究 在博客Android消息机制浅析——基本使用 中,我们介绍了Android消息机制的基本使用以及一些常用方法的使用。本篇,我们就探究下源码。 系列地址: Android消息机制浅析——基本使用 Android消息机制浅析——原理探究 Android消息机制浅析——面试总结一、概述在Android消息机制浅析——基本使用一文中,我们对Android消

钝悟需要时间的打磨,顿悟需要时间的积累 2154

android之Handler消息机制浅析

我们知道,UI操作不是线程安全的,所以我们不准在子线程中操作UI,而大家最常用的就是通过Handler来处理操作UI,那么其中到底是什么机制呢? 我们需要知道几个概念: Handler:在主线程中创建,用来在子线程中发送消息,然后在主线程中处理; Looper:一个线程中只能有一个,用来管理消息队列; Message Queue:消息队列,用来存储通过Handler发送过来的消息;

gsw333的博客 476

浅析Android消息机制 handler之原理分析

前言 在日常的开发过程中我们经常会用到Android消息机制,其中Handler尤为常见。比如当我们执行一些耗时操作,例如读写文件,网络IO时是不建议在主线程也就是UI线程上直接进行,而是重新开一个子线程去完成这些耗时操作,而有一些耗时操作需要更改UI,比如我们需要从网络上下载一些图面显示在界面上,当图片下载完成时,由于Android的机制,子线程是无法更改UI的,所以这时候就需要切换到主线程去更改UI,而这个过程就是由Handler配合完成的。当然更新UI只是Handler的一个功能,它还有更多有趣的功能

QStack的博客 252

Android中消息机制:Handler机制源码浅析

Android中的消息机制一直都是新手头疼的问题,对于Handler机制的理解是Android重中之重,经常在面试和日常开发中遇到,所以,这篇文章目的是通过解析源码来帮助梳理Handler的工作机制和运行流程。

Geek的博客 506
上一篇: View的事件分发机制
下一篇: Kotlin Coroutine 协程Gradle配置
普通网友
博客等级 码龄12年 7粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值