当前位置: 首页 > news >正文

Android随笔-Handler的Message是什么结构

Message 是对象,它就是 Java 中的一个普通类,继承自 Object。但 Android 对它做了大量优化,让它在 Handler 机制中高效复用,避免频繁创建和 GC。

一、Message 的本质

publicfinalclassMessageimplementsParcelable{publicintwhat;// 消息标识publicintarg1,arg2;// 轻量整型参数publicObjectobj;// 任意对象参数publicMessengerreplyTo;// 跨进程回复publiclongwhen;// 消息触发时间Bundledata;// 数据载体Handlertarget;// 目标 HandlerRunnablecallback;// 回调 Runnable// 链表指针,用于消息池Messagenext;// 单链表,指向池中的下一个 Message// 同步锁对象privatestaticfinalObjectsPoolSync=newObject();// 消息池头节点privatestaticMessagesPool;// 消息池当前大小privatestaticintsPoolSize=0;// 消息池最大容量privatestaticfinalintMAX_POOL_SIZE=50;}

核心点

  • Message 是普通 Java 类,不是基本类型,不是 native 结构
  • 但它内部维护了一个静态消息池(sPool),用单链表实现对象复用

二、消息池机制:为什么高效

1. 获取 Message:obtain()

publicstaticMessageobtain(){synchronized(sPoolSync){if(sPool!=null){Messagem=sPool;// 从池头取一个sPool=m.next;// 池头后移m.next=null;// 断开链表m.flags=0;// 重置状态sPoolSize--;// 池大小减1returnm;// 返回复用的对象}}returnnewMessage();// 池空了,才 new}

2. 回收 Message:recycle()

publicvoidrecycle(){if(isInUse()){// 正在使用的消息不能回收return;}recycleUnchecked();}voidrecycleUnchecked(){// 重置所有字段flags=FLAG_IN_USE;what=0;arg1=0;arg2=0;obj=null;replyTo=null;sendingUid=-1;workSourceUid=-1;when=0;target=null;callback=null;data=null;synchronized(sPoolSync){if(sPoolSize<MAX_POOL_SIZE){next=sPool;// 头插法:把自己插到池头sPool=this;// 更新池头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.when=when;Messagep=mMessages;if(p==null||when==0||when<p.when){msg.next=p;// 插到队头mMessages=msg;}else{// 按时间顺序找到插入位置Messageprev;for(;;){prev=p;p=p.next;if(p==null||when<p.when){break;}}msg.next=p;// 插入中间prev.next=msg;}}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,复用消息池Messagemsg=Message.obtain(handler,what,arg1,arg2,obj);handler.sendMessage(msg);// ✅ 正确:用便捷方法,内部也是 obtainhandler.obtainMessage(what).sendToTarget();handler.sendEmptyMessage(what);// ❌ 错误:直接 new,浪费内存Messagemsg=newMessage();// 不要这样

八、总结

Message 是 Java 对象,不是基本类型,也不是 native 结构。Android 用静态单链表维护了一个最大容量 50 的消息池,通过 obtain() 复用、recycle() 回收,避免高频 Handler 场景下的对象创建和 GC。MessageQueue 本身也是用 Message.next 指针串成的按时间排序的单链表——整个 Handler 机制的核心数据结构,就是这一条 Message 链表在消息池和消息队列之间来回流转。

http://www.cnnetsun.cn/news/3609904.html

相关文章:

  • 价格、功能、操作、体验:报名签到查座等会务平台怎么选?看完这篇不纠结
  • AI-Thinker-WB2入门:windows环境配置与工程烧录
  • Python中str、list、tuple、dict、set 五大内置数据结构详解
  • 【雨云】12 元/月打造专属内网穿透:独享 IP、任意端口!
  • 【Java实战】Java加解密算法全解析:分类、场景与国密算法实战总结
  • 2026年做跨境电商,很多人不知道这3个隐形关联流量入口,正被头部大卖悄悄吃透(实战复盘)
  • 抖音黑科技兵马俑总站源头简博科技 | 抖音锚点不合规挂载新规今日生效,短视频引流直播间迈入三端全链路监管时代
  • Kimi K3登顶前端开发榜,月之暗面却遇“算力荒”,还计划最快6个月港股上市!
  • 工业一体机Linux系统部署实战:从系统安装到工业通信环境搭建
  • Claude Code被曝重大隐患,揭开了算法安全的帷幕
  • Ubuntu开发环境搭建(Python-Go-Rust)
  • Google 连发三个新 Gemini 模型,官方宣传与网友差评落差大,Gemini 4 能救场吗?
  • 蓝速 AI 双屏翻译机国际版:全球口音精准适配与商务实效展示
  • 为什么你的AI配乐总被平台降权?——基于127万条审核日志的音频频谱分析报告(含可复用检测清单)
  • python数据可视化技巧的100个练习 -- 38. 交通流量数据可视化的网络流图
  • 下一代企业智能基座:为什么说「LLM 规划 + MCP 调度 + Agent 执行」= 未来标配?一、引言:从工具到系统的智能化跃迁在企业数字化转型的深水区,传统 IT 架构正面临决策滞后、资源割
  • 2026有实力的全球EMBA中立测评,民营企业家择校参考
  • Python企业内部数据治理流程自动化落地的构建路径【教学】
  • Spring Security掌握内容速忆(适用于初学者)
  • 华为鸿蒙免费铃声软件—小羊免费铃声
  • 基于人脸识别的无人值守自习室预约系统设计与实现
  • 高斯泼溅技术-从入门到精通
  • DeepSeek专家模式突破对话上限技巧,无缝衔接新对话!
  • 非结构化数据满天飞,90%的敏感数据藏在文档堆里,怎么让AI真正分得清?
  • 大模型分布式训练与显存优化核心技术解析
  • 因算力紧缺,月之暗面Kimi宣布暂停C端新用户订阅;ASML回应向全球员工发2万欧元股权激励;Qwen3.8-Max预览版上线 | 极客头条
  • 2026年英文论文翻译工具横评:5款主流方案实测对比与效率选型指南
  • UVM验证平台的死亡陷阱:从入门到放弃的那些坑
  • FreeRDP曝高危堆缓冲区溢出漏洞:wfreerdp客户端遭弃用,远程代码执行风险急剧上升
  • 【Springboot毕设全套源码+文档】基于JavaWeb的图书馆管理系统的设计与实现(丰富项目+远程调试+讲解+定制)