尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Android随笔-Handler的Message是什么结构
Message 是对象它就是 Java 中的一个普通类继承自 Object。但 Android 对它做了大量优化让它在 Handler 机制中高效复用避免频繁创建和 GC。一、Message 的本质publicfinalclassMessageimplementsParcelable{publicintwhat;// 消息标识publicintarg1,arg2;// 轻量整型参数publicObjectobj;// 任意对象参数publicMessengerreplyTo;// 跨进程回复publiclongwhen;// 消息触发时间Bundledata;// 数据载体Handlertarget;// 目标 HandlerRunnablecallback;// 回调 Runnable// 链表指针用于消息池Messagenext;// 单链表指向池中的下一个 Message// 同步锁对象privatestaticfinalObjectsPoolSyncnewObject();// 消息池头节点privatestaticMessagesPool;// 消息池当前大小privatestaticintsPoolSize0;// 消息池最大容量privatestaticfinalintMAX_POOL_SIZE50;}核心点Message 是普通 Java 类不是基本类型不是 native 结构但它内部维护了一个静态消息池sPool用单链表实现对象复用二、消息池机制为什么高效1. 获取 Messageobtain()publicstaticMessageobtain(){synchronized(sPoolSync){if(sPool!null){MessagemsPool;// 从池头取一个sPoolm.next;// 池头后移m.nextnull;// 断开链表m.flags0;// 重置状态sPoolSize--;// 池大小减1returnm;// 返回复用的对象}}returnnewMessage();// 池空了才 new}2. 回收 Messagerecycle()publicvoidrecycle(){if(isInUse()){// 正在使用的消息不能回收return;}recycleUnchecked();}voidrecycleUnchecked(){// 重置所有字段flagsFLAG_IN_USE;what0;arg10;arg20;objnull;replyTonull;sendingUid-1;workSourceUid-1;when0;targetnull;callbacknull;datanull;synchronized(sPoolSync){if(sPoolSizeMAX_POOL_SIZE){nextsPool;// 头插法把自己插到池头sPoolthis;// 更新池头sPoolSize;// 池大小加1}}}3. 池结构示意初始状态sPool null, sPoolSize 0 obtain() 第1次池空 → new Message() → 返回新对象 obtain() 第2次池空 → new Message() → 返回新对象 // 两个消息被处理完后 recycle() recycle(msg2): msg2.next null; sPool msg2; sPoolSize 1 recycle(msg1): msg1.next msg2; sPool msg1; sPoolSize 2 // 再次 obtain() obtain(): 取 sPool(msg1); sPool msg2; sPoolSize 1 → 复用 msg1 obtain(): 取 sPool(msg2); sPool null; sPoolSize 0 → 复用 msg2三、为什么不用 new Message()方式结果new Message()堆上分配内存增加 GC 压力Message.obtain()优先从池复用几乎零分配实际效果一个高频 Handler如刷新 UI、动画每秒发 60 条消息用 obtain()前几次 new 之后全部从池复用零 GC用 new Message()每秒 60 个临时对象频繁 Young GC四、MessageQueue 中的 Message 是怎么存的publicfinalclassMessageQueue{MessagemMessages;// 消息队列头按 when触发时间排序的单链表// 入队booleanenqueueMessage(Messagemsg,longwhen){synchronized(this){msg.whenwhen;MessagepmMessages;if(pnull||when0||whenp.when){msg.nextp;// 插到队头mMessagesmsg;}else{// 按时间顺序找到插入位置Messageprev;for(;;){prevp;pp.next;if(pnull||whenp.when){break;}}msg.nextp;// 插入中间prev.nextmsg;}}returntrue;}}关键MessageQueue 本身也是用Message 的单链表实现不是数组不是队列类。Message.next 同时服务于两个链表消息池链表复用消息队列链表按时间排序五、与 Handler、Looper 的关系Looper.prepare() → 创建 Looper MessageQueue ↓ Looper.loop() → 无限循环 ├── MessageQueue.next() → 取消息阻塞/等待 │ └── 没到时间 → nativePollOnce() 休眠 │ └── 到时间了 → 返回 Message ├── msg.target.dispatchMessage(msg) → Handler 处理 │ └── msg.recycleUnchecked() → 回收到消息池 └── 继续循环六、常见误区误区真相“Message 是基本类型”❌ 是对象但用池复用“MessageQueue 用数组”❌ 用 Message 单链表“new Message() 和 obtain() 一样”❌ obtain() 优先复用性能差很多“消息池无限大”❌ 最大 50 个满了直接丢弃不回收“recycle() 后消息还能用”❌ 回收后字段全清空再用是未定义行为七、最佳实践// ✅ 正确用 obtain复用消息池MessagemsgMessage.obtain(handler,what,arg1,arg2,obj);handler.sendMessage(msg);// ✅ 正确用便捷方法内部也是 obtainhandler.obtainMessage(what).sendToTarget();handler.sendEmptyMessage(what);// ❌ 错误直接 new浪费内存MessagemsgnewMessage();// 不要这样八、总结Message 是 Java 对象不是基本类型也不是 native 结构。Android 用静态单链表维护了一个最大容量 50 的消息池通过 obtain() 复用、recycle() 回收避免高频 Handler 场景下的对象创建和 GC。MessageQueue 本身也是用 Message.next 指针串成的按时间排序的单链表——整个 Handler 机制的核心数据结构就是这一条 Message 链表在消息池和消息队列之间来回流转。
RELATED

相关推荐

从交易到社群:车主服务生态的构建与用户价值延伸

从交易到社群:车主服务生态的构建与用户价值延伸

在汽车行业增量时代,经销商的核心目标是卖车,交易完成即意味着服务结束。而进入存量时代后,获客成本持续攀升,老用户的价值愈发凸显。只做一锤子买卖的经销商,会越来越难生存;能够构建车主服务生态&#xf…

📅 2026/8/24 1:24:39
WAIC2026产业信号:一人AI创业全指南

WAIC2026产业信号:一人AI创业全指南

WAIC2026产业信号:一人AI创业全指南写在最前面🌌你好!这里是 晓雨的笔记本 在所有感兴趣的领域扩展知识,感谢你的陪伴与支持~ 👋 欢迎添加文末好友,不定期掉落福利资讯 写在最前面 版权声明:本文…

📅 2026/9/2 15:49:16
ISP ToneMap:原理、必要性与应用场景

ISP ToneMap:原理、必要性与应用场景

摘要 ISP ToneMap(色调映射)是图像信号处理器(ISP)中的核心算法,负责将传感器捕获的高动态范围(HDR)数据智能压缩并映射到标准动态范围(SDR)显示设备上。它解决了现实世界广阔亮度范围与显示设备有限能力之间的根本矛盾,通过全局或局部映射算法,在保留高光和阴影细…

📅 2026/9/1 14:50:35
MORE NEWS

更多资讯

📰

VisiData 命令检索实战指南:Command Palette 与 Commands Sheet 的完整用法

数据分析CLI数据可视化 【免费下载链接】visidata A terminal spreadsheet multitool for discovering and arranging data 项目地址: https://gitcode.com/gh_mirrors/vi/visidata 点击查看 免费下载 导读 VisiData 是一个键盘驱动的终端表格工具,内置…

📰

中药材入门必看:5种药食同源原料清单与选购鉴别指南

身边越来越多朋友开始研究中药材,但一个很现实的问题卡在第一步:进了药店,货架上几十种饮片,每个标签上都写着功效,到底该囤哪几样才不踩坑?今天直接把这份我个人常年回购的“正规中药材原料清单”拿出来聊…

📰

RabbitMQ面试实战指南:从选型对比到权限排查全解析

最近带团队做技术面试复盘时发现一个很有意思的现象:聊到"RabbitMQ面试题"这个概念,绝大多数候选人能顺畅背出交换机类型、确认机制、死信队列这些名词,但只要面试官把问题换成"你现在要重新搭一套消息架构,用Rabb…

📰

ax调度是什么?从贝叶斯优化到自动试验循环的完整实战解析

最近后台总有朋友问我同一个问题:你说的ax调度到底是什么?其实我第一次看到“ax调度”这个说法也愣了一下,后来才明白,大家说的就是把Meta开源的Ax平台用起来。Ax本身是一个面向自适应试验的开源平台,它最早用于内部的…

📰

Atlas 300V 24G推理卡部署YOLO全流程实战:从环境配置到性能调优

这个项目标题只有“atlas”加上两个热度很高的关联搜索词:“atlas部署yolo”和“atlas 300v 24g 是运算加速卡吗”,看起来像是在挑选硬件和推理方案。我最近正好在搞Atlas 300V系列卡的部署,这卡在国产推理卡里话题度确实高,24G显…

📰

Docker 部署 Hermes 智能体:接入 DeepSeek 与工作流编排实战

1. 为什么要在本地用 Docker 跑 Hermes 智能体第一次接触 Hermes 智能体的人,十有八九会卡在同一个地方:官方文档给的是"云端一键部署"或者"桌面版双击安装",但真到自己手里那台常年开着一堆服务的机器上,就发…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬