必看2

1、Handler 机制四大角色是什么?各自作用?

答案

  • Handler:发送消息、处理消息、切换线程(子线程发消息,主线程更新 UI)。
  • Message:消息载体,存放 what、arg1、arg2、obj、执行时间 when。
  • MessageQueue :消息队列,底层单向链表,按执行时间排序,存放所有 Message。
  • Looper :消息轮询器,死循环不断从 MessageQueue 取消息,分发给 Handler 处理。

2、Handler 整体运行流程?

答案

子线程通过 Handler 发 Message → 消息存入 MessageQueue 排队 → Looper 无限循环从队列取消息 → 回调给对应 Handler 的 handleMessage → 主线程执行更新 UI。

3、Looper 原理是什么?为什么不会卡死 ANR?

答案

Looper 是死循环 ,不停调用 MessageQueue.next ();队列无消息或未到延时时间时,底层靠 epoll 阻塞休眠,释放 CPU,不占用主线程资源,所以不会 ANR。

4、MessageQueue 底层是什么结构?

答案

底层是单向链表,不是数组队列;

when 执行时间 从小到大排序,时间早的排在前面,方便 Looper 按时间取消息。

5、Message 为什么推荐用 obtain () 而不是 new Message ()?

答案

Message 内部有消息缓存池(静态链表);

obtain () 从缓存池复用对象,避免频繁 new 创建对象、减少 GC;

用完 recycle () 回收放回缓存池。

6、延时消息 postDelayed /sendMessageDelayed 底层怎么实现延时?

答案

  1. 不开启定时器、不轮询倒计时;
  2. 计算 当前时间 + 延时时间 赋值给 Message 的 when;
  3. 消息按 when 时间插入 MessageQueue 链表有序排队;
  4. Looper 取消息时,没到执行时间就阻塞等待,时间到自动唤醒执行。

7、主线程为什么可以直接 new Handler?不用手动创建 Looper?

答案

App 主线程 ActivityThread 的 main 方法里,已经默认调用了 Looper.prepare() + Looper.loop()

主线程自带 Looper 和 MessageQueue,所以直接 new Handler 就能用。

8、子线程可以直接 new Handler 吗?会报错吗?怎么解决?

答案

子线程直接 new Handler 会报错,因为没有 Looper

解决:手动执行Looper.prepare()new Handler()Looper.loop()

9、Handler 会造成内存泄漏吗?原因怎么解决?

答案

会泄漏。

原因:匿名内部类 Handler 隐式持有 Activity 引用,延时消息没执行完,页面 finish 后 Handler 还在排队持有 Activity,GC 无法回收。

解决:

  1. 使用静态内部类 + 弱引用持有 Activity;
  2. 页面销毁 onDestroy 调用 removeCallbacksAndMessages(null) 清空所有消息。

10、什么是消息屏障、同步消息、异步消息?

答案

  • 同步屏障:往队列插一个特殊标记,只放行异步消息,卡住普通同步消息;
  • 用来优先执行 UI 绘制、刷新界面,保证绘制优先级最高。

11、Intent 大数据不行,Handler 能跨进程通信吗?

答案

普通 Handler 只同进程内线程间通信;不能跨进程;跨进程用 Binder、AIDL。

12、Looper 的 loop () 是死循环,为什么不会耗 CPU?

答案

无消息或延时未到,MessageQueue 底层Linux epoll 阻塞,线程休眠放弃 CPU;有消息才唤醒,几乎不耗性能。

13、postDelayed 延时消息原理

1、 先记住核心一句话

根本没有单独开定时器、也没有子线程倒计时,只是记了个「未来执行时间」,插到队列里排队,Looper 等到点再执行。

2. 发延时消息时

你调用 postDelayed(Runnable, 1000)系统做两件事:

  1. 当前系统时间 + 你设置的延时 1000 毫秒
  2. 算出一个未来准确时间点 when,塞到 Message 里面
3. 消息入队

把这条带 when 时间 的 Message,插入 MessageQueue 单向链表 。队列是按时间从小到大排序的:

  • 时间越早的排越前面
  • 延时久的排后面
4. Looper 不停干活

Looper 死循环调用 MessageQueue.next() 拿消息:

  • 拿到队头消息,先对比 现在时间 和 消息 when 时间
  • 还没到时间 :线程直接阻塞休眠,不轮询、不耗 CPU
  • 时间到了:立刻唤醒线程,取出消息,交给 Handler 执行
5. 极简背诵版

postDelayed 先计算当前时间加延时时长,生成未来执行时间 when 存入 Message;消息按时间有序插入 MessageQueue;Looper 循环取消息,未到执行时间就阻塞休眠,时间到再唤醒分发执行,全程无需额外定时器。

相关推荐
重生之小比特2 小时前
【MySQL 数据库】复合查询
android·数据库·mysql
用户86022504674722 小时前
Jetpack Activity 完整示例教程
android
simplepeng2 小时前
如何减少 89% 的重组,每个Compose开发者都需要的技巧 - derivedStateOf
android·android jetpack
Android 开发者2 小时前
这次,Android 大有不同
android
A8ai2 小时前
Gemini大升级、AI眼镜首发、Android XR亮相,13天后见分晓
android·人工智能·xr
YF02112 小时前
Android 物理摇杆按键映射技术详解
android·游戏
Kapaseker2 小时前
Kotlin inline:你以为它只是个性能优化?
android·kotlin
humors2213 小时前
全平台日常使用的国外应用
android·ios·app·安卓·应用·国外
黄林晴3 小时前
重磅更新!Kotlin协程1.11.0 发布,Flow/StateFlow 新 API 全面升级
android·kotlin