必看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 循环取消息,未到执行时间就阻塞休眠,时间到再唤醒分发执行,全程无需额外定时器。

相关推荐
小田的博客18 小时前
SAP MM 供应商银行主数据更新报错!message R1228!
android·java·服务器
一笑的小酒馆19 小时前
Android智能猫砂盆视频加载慢卡顿问题分析
android
只会cv的小前端21 小时前
七巧低代码服务端脚本使用方法
android·低代码·rxjava
21 小时前
Android 自定义 View 实战:从零打造工业级全向摇杆控件(OmniJoystickView)
android·kotlin·自定义view·摇杆控件
雨白21 小时前
深入理解 Kotlin 协程 (十一):以逸待劳,探秘 select 多路复用与并发安全策略
android·kotlin
hunterandroid1 天前
[Android 从零到一] Android 深度链接与 App Links:从 URI Scheme 到可验证的应用跳转
android
我命由我123451 天前
Jetpack Compose - Material Design 断点范围、WindowSizeClass、针对不同屏幕尺寸创建预览、四类导航栏
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
执明wa1 天前
Android 开发中的设计模式入门:六大设计原则
android·设计模式
松仔log2 天前
Java中级——组合和继承
android·java·开发语言
我命由我123452 天前
Jetpack Compose - MaterialExpressiveTheme 与 MaterialTheme、ColorScheme
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime