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

handler机制原理面试总结

1. 定义与作用 (核心目的):

Handler 是 Android 中用于线程间通信的一种机制,主要用于解决后台线程执行耗时操作后需要更新 UI 的问题。因为 Android 规定 UI 操作必须在主线程(UI 线程)中进行,而耗时操作(如网络请求、文件读写)应在子线程执行。Handler 提供了一种安全的方式让子线程将消息或任务发送到主线程去执行,从而更新 UI。

2. 核心组件及其关系:

  • Handler 消息的发送者和处理者。它负责:
    • MessageRunnable 对象发送到关联的 MessageQueue 中。
    • 在关联的 LooperMessageQueue 取出消息后,处理该消息(执行其 handleMessage 方法或 Runnablerun 方法)。
  • Message 消息的载体。可以携带简单的数据(如 intStringObject)或表示一个任务。
  • MessageQueue 一个先进先出(FIFO)的消息队列。它存储由 Handler 发送过来的 MessageRunnable。每个线程最多只能有一个 MessageQueue
  • Looper 消息循环器。它不断地从关联的 MessageQueue 中取出 MessageRunnable,并将其分派给对应的 Handler 处理。每个线程最多只能有一个 Looper
  • 关系:
    • 一个 Looper 绑定一个线程(通常是主线程)和一个 MessageQueue
    • 一个 Handler 绑定一个 Looper(从而也绑定了该 Looper 所在的线程和 MessageQueue)。
    • Handler 发送 Message 到绑定的 LooperMessageQueue 中。
    • Looper 循环地从 MessageQueue 取消息,并调用目标 HandlerhandleMessage 方法来处理。

3. 工作原理流程:

  1. 初始化: 在目标线程(通常是主线程)中,系统会自动创建 LooperMessageQueue(主线程不需要手动创建 Looper)。在子线程中,需要手动调用 Looper.prepare() 创建 LooperMessageQueue,然后调用 Looper.loop() 启动消息循环。
  2. 创建 Handler: 在目标线程中创建 Handler 对象(例如在主线程的 ActivityFragment 中创建)。这个 Handler 会自动关联到该线程的 LooperMessageQueue
  3. 发送消息: 在子线程中:
    • 可以通过 HandlersendMessage(Message msg)sendMessageDelayedpost(Runnable r)postDelayed 等方法发送消息或任务到关联的 MessageQueue
    • 这些方法内部会将消息放入目标线程的 MessageQueue 中排队。
  4. 消息循环: 目标线程的 Looper 持续运行(loop() 方法),不断检查 MessageQueue
    • 如果队列为空,Looper 会阻塞(进入休眠状态)。
    • 如果队列非空,Looper 取出队头的消息。
  5. 消息处理: Looper 将取出的消息分派给创建该消息的 Handler(即 msg.target)。Handler 调用其 handleMessage(Message msg) 方法(处理 Message)或在目标线程执行 Runnablerun() 方法(处理 Runnable)。这一步发生在目标线程(通常是主线程),因此可以安全地更新 UI。

4. 关键点强调:

  • 线程关联性: Handler 必须在其关联线程(即创建它的线程)中处理消息。这是保证 UI 操作在主线程执行的关键。
  • 避免内存泄漏:ActivityFragment 中使用 Handler 时,如果 Handler 持有对 Activity 的隐式引用(如匿名内部类),而消息队列中还有该 Handler 的消息,会导致 Activity 无法被回收,造成内存泄漏。解决方案:
    • 使用静态内部类 Handler + 弱引用 WeakReference 持有 Activity
    • ActivityonDestroy() 中移除所有待处理的消息:handler.removeCallbacksAndMessages(null)
  • 同步屏障与异步消息:默认情况下所有消息都是同步的。同步屏障是一种特殊的消息(targetnull),它的作用是阻止其后所有的同步消息,只允许异步消息(通过setAsynchronous(true)标记)被处理。这为高优先级任务(如UI绘制、VSYNC信号)开辟了“快速通道”
  • looper.loop()为何不卡死主线程Looper.loop()内部是一个死循环,但主线程并未卡死。关键在于,当消息队列为空时,Looper会通过Linux的epoll机制在Native层阻塞,释放CPU资源。当有新消息入队时,它会被唤醒并继续工作。ANR的发生并非因为循环本身,而是因为某个消息的处理时间过长(如耗时操作放在主线程),导致系统无法响应其他用户输入。
  • 应用场景: 除了子线程更新 UI,Handler 还常用于执行延时任务 (postDelayed)、消息调度等。

5. 简洁总结:

Handler 机制是 Android 异步处理的核心之一。它通过 Handler(发送和处理)、Message(消息载体)、MessageQueue(消息队列)和 Looper(消息循环)四个组件的协作,实现了跨线程(主要是子线程到主线程)的安全通信,确保耗时操作后的 UI 更新在主线程安全执行。理解其内部流程和避免内存泄漏是使用好 Handler 的关键。

6.面试遇到不会的点

(1)哪些是同步消息,哪些是异步消息?

我当时理解错了,应该按照这个思路走

消息类型

特征

创建方式

处理优先级

典型应用场景

同步消息

msg.target不为null,指向发送它的Handler

通过默认Handler的post(Runnable)sendMessage()系列方法发送

正常按时间顺序处理,可被屏障消息阻塞

绝大部分常规的线程间通信,如子线程通知主线程更新UI

异步消息

msg.target不为null,且被标记了 FLAG_ASYNCHRONOUS标志

1. 调用Message.setAsynchronous(true)


2. 使用异步Handler(构造函数参数asynctrue)发送消息

当存在屏障消息时,会优先于同步消息被处理

高优先级的任务,如屏幕垂直同步(VSync)信号触发的UI绘制

屏障消息

msg.target为null

通过MessageQueue.postSyncBarrier()方法插入

本身不被处理,作用是屏蔽后续的同步消息,只允许异步消息通过

为异步消息创建优先处理环境,通常成对使用(添加后需移除)

(2)handler怎么处理postDelayed延迟消息

  1. 消息的封装与发送

    当你调用handler.postDelayed(runnable, delayMillis)时,Handler会首先将Runnable对象封装成一个Message,并将其callback字段指向你的Runnable。接着,它会计算消息的目标执行时间点(when),这个时间点是系统开机到当前的时间(SystemClock.uptimeMillis())加上你设定的延迟时间。然后,这个消息会被送入与当前线程关联的MessageQueue中。

  2. 消息的有序入队

    MessageQueue内部维护了一个按when字段升序排列的单链表。新的消息到来时,并不会简单地加到队尾,而是会遍历链表,找到第一个执行时间比自己晚的消息,然后插入到它之前,从而保证队列总是按执行时间排序的。如果新消息需要被插入到链表头部,并且此时Looper正因处理延迟消息而阻塞,则会通过nativeWake方法唤醒线程,以便重新检查消息队列。

  3. 消息的取出与执行

    在Looper的loop()循环中,会不断调用MessageQueue.next()方法尝试获取下一条消息。该方法会检查队列头部的消息:

    • 如果还没有到执行时间,它会计算需要等待的时间差,然后调用nativePollOnce(ptr, timeoutMillis)方法,让线程进入指定时间的阻塞等待状态,从而释放CPU资源

    • 一旦等待超时(时间到了),或者有新的、更紧急的消息(如执行时间更早的消息)入队并唤醒了线程,next方法就会返回这条消息。Looper随后将消息分发给对应的Handler,最终执行你提交的Runnable任务

(3)handler的message消息队列使用的链表是哪种

MessageQueue(消息队列)内部是使用一个单链表来存储和管理 Message对象的

为何使用单链表?

选择单链表作为底层数据结构,主要是基于消息队列的核心操作需求:

  • 高效的插入操作:消息队列最主要的操作之一是插入新消息(enqueueMessage)。由于消息是按执行时间排序的,新消息需要插入到链表中合适的位置。单链表在中间插入或删除节点时效率很高,只需要修改指针的指向,而不需要像数组那样进行大量的数据移动

  • 灵活的排序需求MessageQueue需要根据延迟时间(postDelayed)等因素对消息进行排序。单链表结构可以灵活地支持这种按时间顺序的插入

http://www.dtcms.com/a/588995.html

相关文章:

  • 人工智能备考——1.2.1-1.2.5总结
  • SQL50+Hot100系列(11.9)
  • vue-router相关理解
  • 怎么做才能设计出好的网站网站充值这么做
  • Qt QWidget点击信号全解析:从基础交互到高级实战
  • 【Spark】操作记录
  • Vue 项目实战《尚医通》,医院详情菜单与子路由,笔记17
  • Kettle 小白入门指南:从A表到B表的数据清洗实战
  • 莱芜正规的企业建站公司东莞专业网站建设公司
  • 尝试性解读 Hopper 和 BlackWell 架构的硬件缓存一致性及其深远影响
  • 深入解析OpenHarmony USB DDK通信机制:从架构到实战
  • 1.8 分块矩阵
  • 2025年游戏手机市场发展趋势与硬件性能全面解析
  • 一般角度的旋转矩阵的推导
  • tomcat建网站个人域名申请的方法
  • 实训11 正则表达式
  • Electron 如何判断运行平台是鸿蒙系统(OpenHarmony)
  • C++ tuple 学习笔记(笔误请指出)
  • 蒙阴建设局网站衡水网站建
  • 服务器运维(十)SQLite3 配置指南——东方仙盟炼气期
  • 服务器运维(十一)SQLite3 php封装——东方仙盟炼气期
  • 【C++】多态(1):多态定义实现及虚函数的重写
  • Ascend C 算子开发模式全解析:从 Kernel 到工程化
  • 在 Unity 游戏开发中,为视频选择 VP8 还是 H.264
  • 【Java知识】OkHttp一款优秀的http客户端工具
  • 建设好网站为什么读取不到文件网站建设官网多少钱
  • 一个FPGA通加载不同程序实现4K edp和V-by-One
  • 脑科学图像处理软件
  • 【C语言实战(79)】深入C语言单元测试:基于CUnit框架的实战指南
  • 会小二也是做会议网站的小地方做外卖网站怎样