Android Handler机制深度解析
Handler是Android的核心机制,理解它对于深入Android开发至关重要。核心要点4个组件工作流程:发送→入队→循环→分发→处理5个关键问题Looper死循环不会ANR(epoll阻塞)子线程不能更新UI(ViewRootImpl检查)Handler内存泄漏(静态类+弱引用)主线程Looper自动创建(ActivityThread)Message对象池(复用避免GC)关键原则1. 使用M
Android Handler机制深度解析
阅读时间: 24分钟
适合人群: Android开发者
你将收获: 彻底理解Handler机制,掌握消息循环原理
一个让面试官满意的回答
2022年春天,我面试字节跳动Android岗位。
面试官:“Handler机制你了解吗?”
我(自信):“了解,Handler用来在线程间通信,主要用于子线程更新UI。”
面试官:“那你能说说Handler、Looper、MessageQueue的关系吗?”
我:“Handler发送消息,Looper循环处理消息,MessageQueue存储消息。”
面试官:“为什么子线程不能直接更新UI?”
我:“因为…Android规定的?”
面试官(微笑):“能再深入一点吗?比如,为什么主线程的Looper.loop()是死循环,但界面不会卡死?”
我(懵):“这个…我没深入了解过…”
面试官:“MessageQueue的next()方法会阻塞线程吗?如果会,为什么不会导致ANR?”
我:“我…不知道…”
面试官:“建议你回去深入研究一下Handler的源码。”
结果:面试挂在这一轮。
3个月后,我重新准备,再次面试字节。
面试官:“Handler机制你了解吗?”
我:“了解。Handler是Android的消息机制,核心是一个生产者-消费者模式。让我从源码层面给您讲解…”
(接下来我讲了20分钟,包括Looper的死循环为什么不会ANR、MessageQueue的阻塞原理、IdleHandler的应用场景、同步屏障的作用…)
面试官:“不错,看得出你确实深入研究过源码。”
结果:这轮满分通过,最终拿到offer。
这次经历让我明白:很多看似简单的机制,背后隐藏着精妙的设计。
今天,我想把Handler机制彻底讲透,让你在面试和实战中都游刃有余。
Handler的4个核心组件
Handler机制 = 4个核心组件的协作
┌─────────────────────────────────────────┐
│ Android消息机制架构 │
├─────────────────────────────────────────┤
│ │
│ Handler │
│ ├─ 发送消息(send/post) │
│ └─ 处理消息(handleMessage) │
│ ↓ │
│ MessageQueue │
│ ├─ 存储消息(按时间排序) │
│ └─ 取出消息(next) │
│ ↓ │
│ Looper │
│ ├─ 循环读取消息(loop) │
│ └─ 分发消息给Handler │
│ ↓ │
│ Message │
│ └─ 消息载体(what/obj/data) │
│ │
└─────────────────────────────────────────┘
1. Message:消息载体
// Message的主要字段
class Message {
int what; // 消息类型
int arg1; // 整型参数1
int arg2; // 整型参数2
Object obj; // 对象参数
Bundle data; // 复杂数据
Handler target; // 目标Handler
Runnable callback; // 回调
long when; // 执行时间
Message next; // 下一个消息(链表)
}
// 创建Message
val msg = Message.obtain() // ✅ 推荐:从对象池获取
msg.what = 1
msg.obj = "data"
// ❌ 不推荐:new Message()
val msg = Message() // 不会复用对象
2. MessageQueue:消息队列
// 简化的MessageQueue
class MessageQueue {
Message mMessages; // 链表头
// 插入消息(按时间排序)
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
msg.when = when;
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
// 插入到头部
msg.next = p;
mMessages = msg;
} else {
// 找到合适的位置插入
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
}
msg.next = p;
prev.next = msg;
}
}
return true;
}
// 取出消息
Message next() {
for (;;) {
long now = SystemClock.uptimeMillis();
Message msg = mMessages;
if (msg != null) {
if (now < msg.when) {
// 未到执行时间,阻塞
int timeout = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
nativePollOnce(ptr, timeout); // native层阻塞
} else {
// 到达执行时间,返回消息
mMessages = msg.next;
return msg;
}
} else {
// 队列为空,无限阻塞
nativePollOnce(ptr, -1);
}
}
}
}
3. Looper:消息循环
// 简化的Looper
class Looper {
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
// 准备Looper
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
}
// 开始循环
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
for (;;) { // 死循环
Message msg = queue.next(); // 取消息(可能阻塞)
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
msg.target.dispatchMessage(msg); // 分发消息
} finally {
msg.recycleUnchecked(); // 回收消息
}
}
}
}
4. Handler:消息处理器
// 简化的Handler
class Handler {
final Looper mLooper;
final MessageQueue mQueue;
public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
}
// 发送消息
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
msg.target = this;
return queue.enqueueMessage(msg, uptimeMillis);
}
// 分发消息
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 优先执行Runnable
msg.callback.run();
} else {
// 调用handleMessage
handleMessage(msg);
}
}
// 处理消息(子类重写)
public void handleMessage(Message msg) {
// 空实现
}
}
Handler的工作流程
完整流程图
线程A(子线程) 主线程
│ │
│ 1. 创建Message │ Looper.prepare()
│ msg = Message.obtain() │ ↓
│ msg.what = 1 │ 创建Looper
│ │ 创建MessageQueue
│ 2. 发送消息 │
│ handler.sendMessage(msg)│
│ │ │
│ └──────────────────→ 3. 入队
│ │ queue.enqueueMessage()
│ │ ↓
│ │ 4. Looper.loop()
│ │ for(;;) {
│ │ msg = queue.next()
│ │ ↓
│ │ 5. 分发消息
│ │ msg.target.dispatchMessage()
│ │ ↓
│ │ 6. 处理消息
│ │ handleMessage(msg)
│ │ }
代码演示
// 主线程(已有Looper)
class MainActivity : AppCompatActivity() {
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
when (msg.what) {
1 -> {
// 更新UI
binding.textView.text = msg.obj as String
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 子线程发送消息
Thread {
val data = fetchDataFromNetwork()
val msg = Message.obtain()
msg.what = 1
msg.obj = data
handler.sendMessage(msg) // 发送到主线程
}.start()
}
}
// 子线程(需手动创建Looper)
class WorkerThread : Thread() {
lateinit var handler: Handler
override fun run() {
Looper.prepare() // 1. 创建Looper
handler = object : Handler(Looper.myLooper()!!) {
override fun handleMessage(msg: Message) {
// 处理消息
println("Received: ${msg.what}")
}
}
Looper.loop() // 2. 开始循环
}
}
深入理解:5个关键问题
问题1:为什么Looper.loop()是死循环,主线程不会ANR?
误解:死循环会导致主线程卡死。
真相:
// Looper.loop()的简化代码
public static void loop() {
for (;;) { // 死循环
Message msg = queue.next(); // ← 关键:会阻塞
if (msg == null) {
return; // 退出循环
}
msg.target.dispatchMessage(msg);
}
}
// MessageQueue.next()
Message next() {
for (;;) {
if (消息队列为空) {
nativePollOnce(ptr, -1); // ← 关键:native层阻塞,释放CPU
}
if (有消息 && 到达执行时间) {
return msg;
}
}
}
关键点:
1. MessageQueue.next()会调用nativePollOnce()
2. nativePollOnce()是Linux的epoll机制
3. 当队列为空时,线程进入休眠,不占用CPU
4. 当有新消息时,native层会唤醒线程
5. 因此,死循环不会导致CPU 100%,也不会ANR
ANR的定义:
- 主线程被阻塞5秒(输入事件)
- 主线程被阻塞10秒(BroadcastReceiver)
Looper.loop():
- 队列为空时:线程休眠,不占CPU ✅
- 有消息时:立即唤醒处理 ✅
- 只要消息处理不超时,就不会ANR ✅
问题2:为什么子线程不能直接更新UI?
误解:Android禁止子线程操作UI。
真相:
// ViewRootImpl.checkThread()
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views."
);
}
}
// 为什么这样设计?
// 1. UI组件不是线程安全的
// 2. 如果允许多线程访问UI,需要加锁
// 3. 加锁会严重影响UI性能
// 4. 因此Android选择:只允许创建View的线程访问
// 实际上,在ViewRootImpl创建前,可以在子线程更新UI
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Thread {
// ✅ 在ViewRootImpl创建前可以
binding = ActivityMainBinding.inflate(layoutInflater)
binding.textView.text = "Hello"
}.start()
Thread.sleep(100)
setContentView(binding.root) // ViewRootImpl在这里创建
Thread {
// ❌ ViewRootImpl创建后不行
binding.textView.text = "World" // 💥 崩溃
}.start()
}
}
问题3:Handler为什么可能造成内存泄漏?
// ❌ 泄漏示例
class MainActivity : AppCompatActivity() {
// 非静态内部类,隐式持有外部类引用
private val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
// 访问Activity
binding.textView.text = "Updated"
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 发送延迟消息
handler.sendEmptyMessageDelayed(0, 60000) // 1分钟后执行
}
// 问题:
// 1. Handler持有Activity引用
// 2. Message持有Handler引用
// 3. MessageQueue持有Message引用
// 4. 如果Activity finish,但Message还在队列中
// 5. Activity无法被GC → 内存泄漏
}
// ✅ 解决方案1:静态Handler + WeakReference
class MainActivity : AppCompatActivity() {
private val handler = MyHandler(this)
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null) // 移除所有消息
}
class MyHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) {
private val activityRef = WeakReference(activity)
override fun handleMessage(msg: Message) {
activityRef.get()?.let { activity ->
if (!activity.isFinishing) {
activity.binding.textView.text = "Updated"
}
}
}
}
}
// ✅ 解决方案2:使用lifecycleScope(推荐)
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
delay(60000)
binding.textView.text = "Updated"
}
// Activity销毁时自动取消
}
}
问题4:主线程的Looper是何时创建的?
// ActivityThread.main()
public static void main(String[] args) {
// ...
Looper.prepareMainLooper(); // 创建主线程Looper
// ...
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// ...
Looper.loop(); // 开始主线程消息循环
throw new RuntimeException("Main thread loop unexpectedly exited");
}
// Looper.prepareMainLooper()
public static void prepareMainLooper() {
prepare(false); // quitAllowed = false,主线程Looper不能退出
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
// 因此:
// 1. 主线程的Looper在应用启动时自动创建
// 2. 开发者不需要手动调用prepare()和loop()
// 3. 子线程需要手动创建Looper
问题5:Message对象池是如何工作的?
// Message的对象池实现
public final class Message {
private static Message sPool; // 对象池头部
private static int sPoolSize = 0; // 池大小
private static final int MAX_POOL_SIZE = 50; // 最大50个
Message next; // 链表
// 从对象池获取(推荐)
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message(); // 池为空,创建新对象
}
// 回收到对象池
void recycleUnchecked() {
// 清空所有字段
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
// ...
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
}
// 为什么使用对象池?
// 1. Message创建和回收非常频繁
// 2. 对象池避免频繁GC
// 3. 提升性能
// 因此:
Message msg = Message.obtain(); // ✅ 推荐
Message msg = new Message(); // ❌ 不推荐
Handler的高级用法
1. IdleHandler:空闲时执行任务
// IdleHandler:当MessageQueue空闲时执行
Looper.myQueue().addIdleHandler {
// 队列空闲时执行
Log.d("IdleHandler", "Queue is idle")
// 返回false:执行一次后移除
// 返回true:每次空闲都执行
false
}
// 实际应用:启动优化
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
// 关键任务:立即执行
initCrashReport()
initLogger()
// 非关键任务:空闲时执行
Looper.myQueue().addIdleHandler {
initImageLoader() // 图片加载库
initAnalytics() // 统计SDK
initPush() // 推送SDK
false
}
}
}
2. 同步屏障:优先处理异步消息
// 同步屏障机制(系统内部使用)
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
// View绘制时使用同步屏障
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 设置同步屏障
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 发送异步消息
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL,
mTraversalRunnable,
null
);
}
}
// 为什么需要同步屏障?
// 1. 保证UI绘制的高优先级
// 2. 即使MessageQueue中有其他消息
// 3. 也会优先处理UI绘制
// 4. 避免掉帧
3. HandlerThread:带Looper的线程
// HandlerThread:自带Looper的工作线程
class MyService : Service() {
private lateinit var handlerThread: HandlerThread
private lateinit var handler: Handler
override fun onCreate() {
super.onCreate()
// 创建HandlerThread
handlerThread = HandlerThread("WorkerThread")
handlerThread.start()
// 获取Looper
handler = Handler(handlerThread.looper)
}
fun doWork() {
handler.post {
// 在WorkerThread中执行
heavyWork()
}
}
override fun onDestroy() {
super.onDestroy()
handlerThread.quitSafely() // 安全退出
}
}
// IntentService内部就是用HandlerThread实现的
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
}
实战案例:倒计时功能
// 使用Handler实现倒计时
class CountdownHandler(private val textView: TextView) : Handler(Looper.getMainLooper()) {
private var remainingSeconds = 0
private val MSG_COUNTDOWN = 1
fun start(seconds: Int) {
remainingSeconds = seconds
sendEmptyMessage(MSG_COUNTDOWN)
}
fun stop() {
removeMessages(MSG_COUNTDOWN)
}
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_COUNTDOWN -> {
if (remainingSeconds > 0) {
textView.text = "${remainingSeconds}s"
remainingSeconds--
sendEmptyMessageDelayed(MSG_COUNTDOWN, 1000)
} else {
textView.text = "Done"
}
}
}
}
}
// 使用
class MainActivity : AppCompatActivity() {
private lateinit var countdownHandler: CountdownHandler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
countdownHandler = CountdownHandler(binding.countdownText)
binding.startButton.setOnClickListener {
countdownHandler.start(60) // 倒计时60秒
}
}
override fun onDestroy() {
super.onDestroy()
countdownHandler.stop() // 停止倒计时
}
}
Handler vs Coroutine
现代Android开发中,很多Handler的使用场景已被Coroutine替代。
// Handler方式
val handler = Handler(Looper.getMainLooper())
Thread {
val data = fetchData()
handler.post {
updateUI(data)
}
}.start()
// Coroutine方式(推荐)
lifecycleScope.launch {
val data = withContext(Dispatchers.IO) {
fetchData()
}
updateUI(data)
}
// 何时还需要Handler?
// 1. 需要精确控制消息时间
// 2. 需要使用MessageQueue的特殊功能(如IdleHandler)
// 3. 与系统底层API交互(如Choreographer)
// 4. 维护老代码
// 新项目推荐:
// - 异步任务:使用Coroutine
// - 线程通信:使用Coroutine + Flow
// - 定时任务:使用Coroutine + delay
总结
Handler是Android的核心机制,理解它对于深入Android开发至关重要。
核心要点:
- 4个组件:Message、MessageQueue、Looper、Handler
- 工作流程:发送→入队→循环→分发→处理
- 5个关键问题:
- Looper死循环不会ANR(epoll阻塞)
- 子线程不能更新UI(ViewRootImpl检查)
- Handler内存泄漏(静态类+弱引用)
- 主线程Looper自动创建(ActivityThread)
- Message对象池(复用避免GC)
关键原则:
1. 使用Message.obtain()而不是new Message()
2. 及时移除消息避免内存泄漏
3. 静态Handler + WeakReference
4. 现代项目优先使用Coroutine
5. Handler用于系统级API交互
记住:
Handler不仅仅是线程通信工具
更是Android消息机制的核心
理解Handler = 理解Android运行原理
当你彻底理解Handler机制,很多Android的设计决策都会豁然开朗。
下一篇预告:《Android事件分发机制:从触摸到响应》
作者: Andy Gong
专注: Android底层机制与源码分析
#Android #Handler #Looper #MessageQueue #消息机制 #源码分析
更多推荐



所有评论(0)