android Handler , Looper , Message , MessageQueue 详解
一、基础Q1请简述 Handler 机制的工作原理核心回答Handler 发送消息 → MessageQueue 按时间排序存储 → Looper 无限循环取出 → 回调 Handler 处理。细节MessageQueue不是队列是单向链表按when触发时间戳排序Looper.loop()中queue.next()无消息时通过native epoll阻塞不消耗 CPU最终msg.target.dispatchMessage(msg)target就是发送该消息的 HandlerQ2一个线程可以有几个 Handler几个 Looper数量原因Looper1 个ThreadLocal存储prepare()时检查重复重复会抛异常Handler多个多个 Handler 可以共享同一个 Looper 和 MessageQueue源码验证java// Looper.prepare() if (sThreadLocal.get() ! null) { throw new RuntimeException(Only one Looper may be created per thread); }Q3为什么主线程的 Looper.loop() 死循环不会导致 ANR核心要点ANR 的本质是消息处理超时不是死循环本身。深入解析loop()中的queue.next()无消息时会通过native 层的epoll_wait阻塞线程释放 CPU有消息来时native 层被唤醒继续执行ANR 发生在dispatchMessage()里处理消息耗时过长如 5s 内未响应输入所以死循环 阻塞 事件驱动模型这是高性能的Q4MessageQueue 的数据结构是什么答案单向链表按when时间戳排序java// Message.java Message next; // 链表指针 long when; // 触发时间为什么不用数组/堆不需要随机访问只取头部 → 链表 O(1)插入按时间排序数量通常不多O(n) 可接受内存更紧凑且支持对象池复用二、进阶深挖Q5Handler 的sendMessageDelayed()是怎么实现延迟的核心原理不是真的延迟发送而是提前发送按时间排队。流程计算when SystemClock.uptimeMillis() delayMillisenqueueMessage()按when插入链表合适位置Looper循环到该消息时检查when是否到达未到计算剩余时间通过nativenativePollOnce(ptr, timeout)阻塞等待已到取出处理Q6Handler 内存泄漏的原因如何解决原因非静态内部类Handler持有外部Activity的引用延迟消息如postDelayed在 Activity 销毁时仍在 MessageQueue 中Message 持有 HandlerHandler→Activity导致 Activity 无法被回收解决方案3种java// 方案1静态内部类 WeakReference private static class SafeHandler extends Handler { private WeakReferenceActivity ref; SafeHandler(Activity activity) { ref new WeakReference(activity); } Override public void handleMessage(Message msg) { Activity activity ref.get(); if (activity ! null !activity.isFinishing()) { // 处理消息 } } } // 方案2Activity.onDestroy() 时移除消息 Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacksAndMessages(null); } // 方案3使用 Lifecycle 组件自动管理Q7Message.obtain() 和 new Message() 有什么区别答案obtain()从消息对象池中复用new会创建新对象。源码javapublic static Message obtain() { synchronized (sPoolSync) { if (sPool ! null) { Message m sPool; sPool m.next; m.next null; m.flags 0; sPoolSize--; return m; } } return new Message(); // 池空时才 new }好处避免频繁 GC提升性能。Android 系统大量消息传递场景如触摸事件、绘制都用这个池。Q8post(Runnable)和sendMessage(Message)有什么区别post(Runnable)sendMessage(Message)本质把 Runnable 赋值给msg.callback直接发送 Message处理优先级高dispatchMessage先检查 callback低使用场景简单任务需要携带复杂数据源码javapublic final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m Message.obtain(); m.callback r; // Runnable 被包装进 callback return m; }Q9IdleHandler 是什么使用场景定义当 MessageQueue 空闲无消息或消息未到触发时间时执行的回调。使用javaLooper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { Override public boolean queueIdle() { // 执行低优先级任务 return false; // true保留false执行完移除 } });经典场景启动优化主线程空闲时加载非关键资源延迟初始化如LeakCanary的初始化UI 收尾如RecyclerView预加载Q10什么是同步屏障Sync Barrier原理插入一个target null的特殊 Message拦截其后所有同步消息只允许异步消息通过。使用场景ViewRootImpl在scheduleTraversals()时插入屏障确保Choreographer的 VSync 异步消息优先执行避免掉帧注意同步屏障是hide API应用层不能直接调用。三、实战场景题Q11如何在子线程中创建 Handlerjavanew Thread(() - { // 子线程默认没有 Looper必须手动创建 Looper.prepare(); Handler handler new Handler(Looper.myLooper()) { Override public void handleMessage(Message msg) { // 在子线程处理 } }; Looper.loop(); // 阻塞开始消息循环 // 退出时子线程可以退出 // Looper.myLooper().quitSafely(); }).start();更推荐使用HandlerThreadjavaHandlerThread thread new HandlerThread(bg); thread.start(); Handler handler new Handler(thread.getLooper());Q12Looper.quit()和quitSafely()的区别quit()quitSafely()行为立即退出清空 MessageQueue设置退出标记处理完已有消息后退出延迟消息直接丢弃丢弃只保证当前已到达的消息使用子线程 Looper子线程 Looper主线程 Looper 不允许 quit会抛异常。Q13主线程的 Looper 是什么时候创建的答案ActivityThread.main()中。java// ActivityThread.java public static void main(String[] args) { Looper.prepareMainLooper(); // 创建主线程 Looper ActivityThread thread new ActivityThread(); thread.attach(false); Looper.loop(); // 开始循环永不退出 }Q14为什么 Handler 构造方法里要求 Looper 不能为 nulljavapublic Handler(Looper looper) { this(looper, null, false); }原因Handler 必须关联一个 MessageQueue 才能发消息MessageQueue 来自 Looper如果当前线程没有调用Looper.prepare()Looper.myLooper()返回 null直接抛异常避免 NPE 或消息丢失Q15触摸事件是怎么通过 Handler 机制传递到 View 的流程InputDispatchernative收到触摸事件通过JNI将事件封装成Message发送到主线程的MessageQueueLooper取出消息ViewRootImpl的WindowInputEventReceiver处理最终分发到DecorView→ViewGroup→View的dispatchTouchEvent()这解释了为什么在主线程执行耗时操作会导致触摸无响应——消息被堵在队列里。四、面试速记口诀问题一句话答案Handler 发消息去哪MessageQueue链表Looper 干嘛的死循环取消息交给 Handler为什么不会卡死native epoll 阻塞有消息才唤醒延迟消息怎么实现提前入队按时间排序到点才处理内存泄漏怎么解静态内部类 WeakReference removeCallbacks子线程用 Handler先Looper.prepare()Looper.loop()

相关新闻

Claude Code进阶指南:解锁Skills、Superpowers与Auto-mode,打造AI编程副驾驶

Claude Code进阶指南:解锁Skills、Superpowers与Auto-mode,打造AI编程副驾驶

1. 项目概述:从“能用”到“好用”的Claude Code进阶之路如果你已经成功在VSCode里装上了Claude Code,体验过它流畅的代码补全和对话,那么恭喜你,你已经迈出了第一步。但说实话,如果只是把它当成一个“更聪明的代码提示…

2026/10/18 8:30:40 阅读更多 →
股权架构决定企业生死

股权架构决定企业生死

初创公司随便分配股权,极易埋下隐患。均分股权、大股东持股不足 67%,后期重大决策容易陷入僵局。合理的股权架构,要保证核心创始人控制权,预留激励份额,提前设置股东进退通道,从源头预防纠纷。

2026/10/18 1:20:32 阅读更多 →
Harness工程:驾驭AI代码智能体的结构化开发范式

Harness工程:驾驭AI代码智能体的结构化开发范式

最近,很多开发者发现,在 GitHub 上搜索“DeepSeek”时,除了官方仓库,一个名为“Deepseek Harness 团队”的公众号开始频繁出现。这引发了不少疑问:这个团队是官方的吗?Harness 到底是什么?它和最…

2026/10/16 21:51:45 阅读更多 →

最新新闻

AR视频巡检落地实践:从人工巡检到智慧运维的完整复盘

AR视频巡检落地实践:从人工巡检到智慧运维的完整复盘

干运维这行的朋友应该都有同感:巡检这件事,看起来简单,做起来全是细节。一群人拿着纸质的或者Excel表格的设备清单,按路线走一圈,看仪表、听声音、摸温度、填记录,回到值班室再手工录入系统。整个过程依赖个…

2026/10/18 19:25:21 阅读更多 →
校园网毕业设计:基于ENSP的拓扑规划与高可用配置实践

校园网毕业设计:基于ENSP的拓扑规划与高可用配置实践

基础设施选型与拓扑架构的心得做校园网类毕设,最容易犯的毛病就是一上来就堆设备。见过不少同学把核心层用三层交换机、汇聚层堆三层、接入层也全三层,结果整张拓扑光设备就二十几台,配置起来自己都兜不住。ENSP里设备种类就那么多&#xff0…

2026/10/18 19:25:21 阅读更多 →
ZYNQ软硬协同实战:FFT频谱分析与打地鼠游戏设计调试

ZYNQ软硬协同实战:FFT频谱分析与打地鼠游戏设计调试

简介:一套基于Xilinx Zynq-7000系列SoC的双项目实战资料,专为FPGA嵌入式课程设计、数字系统综合实践及竞赛备赛人员准备,集成FFT频谱分析与打地鼠交互游戏两个完整可运行的工程方案。压缩包共83个文件,以VHDL工程源码(…

2026/10/18 19:25:21 阅读更多 →
IDEA、VSCode离线插件安装全攻略:把插件市场搬到内网开发机

IDEA、VSCode离线插件安装全攻略:把插件市场搬到内网开发机

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 19:25:21 阅读更多 →
Claude Skills 实战:推荐 5 个高质量 Skills,附 TaoToken 统一 Key 接入配置

Claude Skills 实战:推荐 5 个高质量 Skills,附 TaoToken 统一 Key 接入配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 19:25:21 阅读更多 →
BrowserSkill:基于Chrome DevTools Protocol的轻量级浏览器CLI自动化工具

BrowserSkill:基于Chrome DevTools Protocol的轻量级浏览器CLI自动化工具

1. 项目概述:BrowserSkill不是插件,而是一套浏览器自动化能力的CLI封装体系BrowserSkill这个词最近在开发者社区里频繁出现,但它既不是Chrome商店里某个新上架的视频下载插件,也不是Edge浏览器内置的Copilot功能升级包。我第一次在…

2026/10/18 19:24:21 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →