在 Android 早期开发中,Handler 几乎是“线程切换”的代名词。
更新 UI?
用 Handler。
延迟执行?
用 Handler。
子线程和主线程通信?
还是 Handler。
但到了今天 —— Kotlin 协程成为主流,Jetpack 全面拥抱结构化并发。
协程时代,Handler 还应该在业务代码里存在吗?
一、Handler 曾经解决了什么问题?
Android 的 UI 线程模型决定:
只有主线程可以更新 UI。
于是,基于 Looper + MessageQueue,Android 设计了 Handler 机制。
核心模型:
- 每个线程可以拥有一个 Looper
- Looper 维护一个 MessageQueue
- Handler 负责向队列投递 Message / Runnable
典型代码:
在没有协程的年代,这是标准写法。
二、协程出现后,问题变了
当 Kotlin 协程进入 Android 官方体系:
- lifecycleScope
- viewModelScope
- Dispatchers.Main
- withContext
- 结构化并发
线程切换已经变成:
你会发现:
- 没有显式线程切换
- 没有回调嵌套
- 没有 Handler
- 没有内存泄漏风险
三、Handler 在协程时代的问题
1️⃣ 破坏结构化并发
协程强调:
子任务必须归属于某个 Scope
而 Handler 是 fire-and-forget:
- 谁管理它?
- Activity 销毁了怎么办?
- 任务是否还在跑?
生命周期失控。
2️⃣ 绕过生命周期体系
Jetpack 的优势在于:
- lifecycleScope 自动 cancel
- viewModelScope 跟随 ViewModel 生命周期
而 Handler:
- 不会自动取消
- 需要手动 removeCallbacks
- 容易造成泄漏
3️⃣ 让“线程”暴露到业务层
协程的核心思想之一:
让线程切换成为实现细节
但 Handler 让业务代码感知:
- Looper
- 主线程
- MessageQueue
这是一种抽象倒退。
四、那 Handler 真的要退休吗?
答案是:
在业务层,基本可以退休。
在底层框架层,不会退休。
✔ 业务层建议
- UI → lifecycleScope
- ViewModel → viewModelScope
- Repository → suspend + withContext
- 长任务 → 自建受控 CoroutineScope
✔ 框架层仍然需要
实际上:
Dispatchers.Main底层仍然基于 Handler- lifecycle 内部依然使用 Handler
- 很多系统组件依然依赖 Looper
协程不是取代 Handler。
协程是对 Handler 的抽象升级。
五、真正要退休的是什么?
不是 Handler 这个类。
而是:
在业务层直接使用 Handler。
在协程时代,线程调度应当成为运行时能力,由 CoroutineDispatcher 统一管理,而不是由业务代码手动操作。
一个现代 Android 项目中:
Activity 不应该持有 Handler
ViewModel 不应该 new Handler
Repository 不应该 post Runnable
如果项目里还大量出现 Handler,说明并发模型仍停留在上一个时代。
在业务代码里显式操作线程。
当你写下:
说明:
- 线程边界暴露
- 生命周期未纳入管理
- 并发模型混乱
这才是问题。
六、架构升级的本质
Android 并发模型经历了三代:
1️⃣ AsyncTask 时代
2️⃣ Handler + 线程池时代
3️⃣ 协程 + 结构化并发时代
每一次升级,都是在:
提升抽象层级
收敛异步边界
强化生命周期控制
协程不是语法糖。
它是 Android 架构层的一次并发升级。