Android Hanlder 揭密之路- 深入理解异步消息传递机制Looper、Handler、Message三者关系
feilongw 2025-04-26 05:07 15 浏览
前言
Handler、Looper以及Message之间的关系,概括性来说,Looper负责的是创建一个MessageQueue对象,然后进入到一个无限循环体中不断取出消息,而这些消息都是由一个或者多个Handler进行创建处理
Messagequeue 的数据结构是什么?
基础数据结构中 “先进先出” 的一种数据结构
Handler post 原理
消息是通过 MessageQueen 中的 enqueueMessage()方法加入消息队列中的,并且它在放入中就进行好排序,链表头的延迟时间小,尾部延迟时间最大
- Looper.loop()通过 MessageQueue 中的 next()取消息
- next()中如果当前链表头部消息是延迟消息,则根据延迟时间进行消息队列会 阻塞,不返回给 Looper message,知道时间到了,返回给 message
- 如果在阻塞中有新的消息插入到链表头部则唤醒线程
- Looper 将新消息交给回调给 handler 中的 handleMessage 后,继续调用 MessageQueen的next()方法,如果刚刚的延迟消息还是时间未到,则计算时间继续阻塞
handler.postDelay()的实现是通过MessageQueue中执行时间顺序排列,消息队列阻塞和唤醒的方式结合实现的;如果真的是通过延迟将消息放入到 MessageQueen中,那放入多个延迟消息就要维护多个定时器
Android 消息机制的简介
在 Android 中使用消息机制,我们首先想到的就是 Handler;没错,Handler是 Android 消息机制的上层接口;Handler 的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行。通常情况下,Handler的使用场景就是更新UI
在子线程中,进行耗时操作,执行完操作后,发送消息,通知主线程更新 UI;这便是消息机制的典型应用场景。我们通常只会接触到 Handler 和 Message 来完 成消息机制,其实内部还有两大助手来共同完成消息传递
消息机制的模型 消息机制主要包含: MessageQueue,Handler和Looper这三大部分,以及Message,下面我们一一介绍
- Message:需要传递的消息,可以传递数据;
- MessageQueue:消息队列,但是它的内部实现并不是用的队列,实际上是通过 一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优 势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
- Handler:消息辅助类,主要功能向消息池发送各种消息事件 (Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
- Looper:不断循环执行(Looper.loop),从 MessageQueue中读取消息,按分发机制将消息分发给目标处理者
消息机制的架构
消息机制的运行流程:在子线程执行完耗时操作,当 Handler 发送消息时,将会 调用
MessageQueue.enqueueMessage,向消息队列中添加消息
当通过Looper.loop 开启循环后,会不断地从线程池中读取消息,即调用 MessageQueue.next,然后 调用目标 Handler(即发送该消息的 Handler)的 dispatchMessage 方法传递消息,然后返回到 Handler 所在线程,目标 Handler 收到消息,调用 handleMessage方法,接收消息,处理消息
MessageQueue,Handler 和 Looper 三者之间的关系:每个线程中只能存在一个 Looper,Looper 是保存在 ThreadLocal 中的。主线程(UI 线程)已经创建了一个 Looper,所以在主线程中不需要再创建 Looper,但是在其他线程中需要创建 Looper
每个线程中可以有多个 Handler,即一个Looper 可以处理来自多个 Handler的消息;Looper 中维护一个MessageQueue,来维护消息队列,消息队列中的 Message可以来自不同的 Handler
- Looper 有一个 MessageQueue 消息队列
- MessageQueue 有一组待处理的 Message
- Message中记录发送和处理消息的 Handler
- Handler中有 Looper 和 MessageQueue
我们可以使用 Handler 发送并处理与一个线程关联的 Message 和 Runnable ;(注意:Runnable 会被封装进一个 Message,所以它本质上还是一个 Message ) 每个 Handler 都会跟一个线程绑定,并与该线程的 MessageQueue 关联在一起, 从而实现消息的管理以及线程间通信
- Handler 的背后有着 Looper 以及 MessageQueue 的协助,三者通力合作,分工 明确;尝试小结一下它们的职责,如下:
- Looper :负责关联线程以及消息的分发在该线程下从 MessageQueue 获取 Message,分发给 Handler ;
- MessageQueue :是个队列,负责消息的存储与管理,负责管理由 Handler 发送过 来的 Message ;
- Handler : 负责发送并处理消息,面向开发者,提供 API,并隐藏背后实现的细节 Handler 发送的消息由 MessageQueue 存储管理,并由 Loopler 负责回调消息 到 handleMessage();线程的转换由 Looper 完成,handleMessage() 所在线程由 Looper.loop() 调用 者所在线程决定
Handler 引起的内存泄露原因以及最佳解决方案
Handler 允许我们发送延时消息,如果在延时期间用户关闭了 Activity,那么该 Activity 会泄露
这个泄露是因为 Message 会持有 Handler,而又因为 Java 的特性,内部类会 持有外部类,使得 Activity 会被 Handler 持有,这样最终就导致 Activity 泄露
解决该问题的最有效的方法是:将 Handler 定义成静态的内部类,在内部持有 Activity 的弱引用,并及时移除所有消息
示例代码如下:
private static class SafeHandler extends Handler {
private WeakReference ref;
public SafeHandler(HandlerActivity activity) {
this.ref = new WeakReference(activity);
}
@Override
public void handleMessage(final Message msg) {
HandlerActivity activity = ref.get();
if (activity != null) {activity.handleMessage(msg);
}
}}
并且再在 Activity.onDestroy() 前移除消息,加一层保障:
@Overrideprotected void onDestroy() {
safeHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
这样双重保障,就能完全避免内存泄露了。注意:单纯的在 onDestroy 移除消息并不保险,因为 onDestroy 并不一定执行
- Handler 的 背 后 有 Looper 、 MessageQueue 支 撑 , Looper 负 责 消 息 分 发 , MessageQueue 负责消息管理;
- 在创建 Handler 之前一定需要先创建 Looper;
- Looper 有退出的功能,但是主线程的 Looper 不允许退出;
- 异步线程的 Looper 需要自己调用 Looper.myLooper().quit(); 退出;
- Runnable 被封装进了 Message,可以说是一个特殊的 Message;
- Handler.handleMessage() 所在的线程是 Looper.loop() 方法被调用的线程,也可以说成 Looper所在的线程,并不是创建Handler的线程;
- 使用内部类的方式使用Handler可能会导致内存泄露,即便在 Activity.onDestroy 里移除延时消息,必须要写成静态内部类
Android UI 是线程不安全的,如果在子线程中尝试进行 UI 操作,程序就有可能 会崩溃
相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也 是早已烂熟于心,即创建一个 Message 对象,然后借助 Handler 发送出去,之 后在 Handler 的 handleMessage()方法中获得刚才发送的 Message 对象,然 后在这里进行 UI 操作就不会再出现崩溃了
在主线程中可 以直接创建 Handler 对象,而在子线程中需要先调用 Looper.prepare()才能创 建 Handler 对象
有关 Handler 的知识点就到这里了, 有需要学习更多关于 Handle 知识点的同学,可以 私信 发送 “进阶” 即可 获取一份 学习笔记 ,相信能够帮助大家 查漏补缺
资料部分内容展示如下:
《Handler 机制之 Thread》
- 线程概念
- Android线程的实现
- 线程的阻塞
- 关于线程上下文切换
- 关于线程的安全问题
- 守护线程
- 线程的内存
《Handler机制之ThreadLocal》
- Java中的ThreadLocal
- ThreadLocal的前世今生
- Android中的ThreadLocal
- Android 面试中的关于ThreadLocal的问题
- ThreadLocal的结构
- ThreadLocal静态类ThreadLocal.Values
- ThreadLocal的总结
完整版PDF文档获取方式: 私信 发送 “进阶” 即可 免费获取
对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
Android 架构师之路还很漫长,与君共勉
相关推荐
- Java 智能外呼机器人源码
-
1个电话1分钱,烦人的AI外呼成大模型最成功应用?来源|Tech星球文|王琳说到大模型最成功的应用,你首先想到的可能是对话式机器人Kimi、豆包、文心一言等等,这些月活数百万尚无法盈利,甚至无...
- bios怎么进入win7(bios怎么进入win7旗舰版)
-
华硕B460主板重装win7系统教程以及BIOS设置方法(支持USB)intel第十代酷睿的公布,华硕发布了全新升级系列产品电脑主板,是继Z490电脑主板开售后服务,华硕B460系列产品电脑主板宣布先...
- iToolab UnlockGo for mac(苹果设备解锁工具) v4.5.0激活版
-
iOS设备解锁工具:iToolabUnlockGomac中文版iToolabUnlockGoforMac是一款专业的iOS设备解锁工具,iToolabUnlockGomac版能够在iP...
- arm linux gcc 安装(arm linux gcc命令)
-
「嵌入式」Linux开发工具arm-linux-gcc安装及使用知识架构及层次—程序编译及调试嵌入式交叉编译器安装配置宿主机执行编译、链接嵌入式软件的计算机目标机运行嵌入式软件的硬件平台“本地”编...
- 28推精英会专访IT博主卢松松
-
卢松松:我是创业人前段时间接受了中国青年政治学院的校内媒体《青春报》的一次访谈,那这次访谈主要是针对当代大学生对我目前所做的工作一次了解,也让大学生们对自媒体、站长、草根互联网有一个基本认识。这是一个...
- Android 中怎么使用IActivitymanager
-
Android操作系统之Activity的启动过程前言上篇文章写到Service的启动过程;相对来说Activity的启动过程比Service的启动过程更为复杂,其一Activity的生命...
- codesign 指令集 指令集编程
-
丛京生:可定制计算的设计自动化(感谢ASP-DAC组委会和北京大学罗国杰教授提供照片)我很有幸从第一届亚太地区设计自动化会议(ASP-DAC)起就参与到ASP-DAC这个大家庭。我的第一篇ASP-DA...
- CorelDRAW2023永久免费版图形图像处理软件
-
Mac上的CorelDRAW平面设计软件(cdr2023中文掌握创意的魔杖:畅游Mac上的CorelDRAW中文版亲爱的设计师们,一场设计之旅即将展开!CorelDRAWGraphicsSuit...
- java实现磁力链下载功能 java根据链接下载文件
-
#最值会员#下载会员哪家值?迅雷、QQ旋风、百度云会员对比作者:code54264前言:老夫的Q龄已经年了。从爪机时代的java到原始智能的Symbian再到现在两分天下的Android、ios,无...
- iOS UITextField 切换到表情键盘 ios表情输入法
-
iOS快速集成QQ表情键盘我们常在开发中需要制作常见的类似QQ的表情键盘,如果自己去实现会非常复杂,笔者推荐一个开源项目,集成非常简单。Demo演示:如果是UITextView,导入#import"...
- java windows 浮层 java分层窗格
-
“科技+IP”让中华优秀传统文化焕发新生近日,电影《哪吒2》票房再次刷新历史纪录,登顶全球动画电影票房榜首。《哪吒2》《黑神话:悟空》等围绕中国经典文化IP改编的文化娱乐作品,都以前沿视效技术与中华优...
- 63页战略分析逻辑架构图PPT,满足你对高效率和专业性的所有想象(附下载)
-
页战略分析逻辑架构图PPT模板,品牌营销战略的构成分享职场干货,提升能力!为职场精英打造个人知识体系,升职加薪!页战略分析逻辑架构图PPT模板如何拿到分享的源文件:请您关注本头条号,然后私信本头条号“...
- android屏蔽广告 host管理 爱玩机工具箱
-
彻底屏蔽安卓广告的实用指南,打造无广告安卓手机本内容来源于@什么值得买APP,观点仅代表作者本人|作者:期望氢气球在现代的移动设备中,广告无处不在,无论是在应用程序中还是在网页上。一方面作为安卓开发...
- IDC运维团队组织架构 idc运维工程师职责
-
IT运维岗位可以分为哪几种?个运维岗详解IT运维岗位可以分为哪几种呢?下面和千锋广州小编一起来看看吧!IT运维岗位以工作内容分类大致可以划分为以下几种岗位:IDC机房运维售前运维桌面运维监控运维实施运...
- 「软件架构」InfoQ 软件架构和设计趋势报告2020年4月
-
软件架构可能不是你想象的那个样子软件架构在敏捷社区中存在争议。在许多人的经验中,架构只会导致毫无价值的会议和无关紧要的文件,“地图不是领土”的说法可以恰当地概括这一观点。然而,架构不佳的应用程序很快就...
- 一周热门
- 最近发表
- 标签列表
-