编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • Android提升进阶

    • 库的解读

    • 专栏博客

      • 系统启动Zygote
      • Binder通信原理
      • Handler消息机制
        • 一、引言:为什么需要Handler
        • 二、Handler机制整体架构
          • 2.1 四大核心组件
          • 2.2 消息流转的完整过程
        • 三、MessageQueue的数据结构与实现
          • 3.1 消息队列的链表结构
          • 3.2 消息入队(enqueueMessage)
          • 3.3 消息出队(next)
        • 四、Looper的工作原理
          • 4.1 Looper的创建与准备
          • 4.2 ThreadLocal的工作原理
          • 4.3 Looper.loop():消息循环
        • 五、Handler的消息发送与处理
          • 5.1 消息发送的多种方式
          • 5.2 消息分发优先级
          • 5.3 Handler与Looper的绑定关系
        • 六、Message的复用池机制
          • 6.1 Message的对象池实现
          • 6.2 复用池的设计思想
        • 七、Native层的MessageQueue
          • 7.1 Java层与Native层的关系
          • 7.2 NativeMessageQueue的创建
        • 八、epoll机制与线程休眠
          • 8.1 为什么使用epoll
          • 8.2 nativePollOnce的实现
          • 8.3 nativeWake的实现
        • 九、同步屏障与异步消息
          • 9.1 什么是同步屏障
          • 9.2 同步屏障在ViewRootImpl中的应用
          • 9.3 同步屏障的实现原理
        • 十、IdleHandler机制
          • 10.1 IdleHandler的定义与使用
          • 10.2 IdleHandler在系统中的应用
          • 10.3 IdleHandler的执行时机
        • 十一、HandlerThread与IntentService
          • 11.1 HandlerThread的实现
          • 11.2 IntentService的原理(已废弃但值得了解)
        • 十二、Handler导致的内存泄漏
          • 12.1 泄漏的根本原因
          • 12.2 解决方案
        • 十三、主线程Looper为什么不会ANR
          • 13.1 常见误解
          • 13.2 正确理解
          • 13.3 ANR的检测机制
        • 十四、面试高频问题与深度分析
          • 14.1 一个线程可以有几个Handler?几个Looper?几个MessageQueue?
          • 14.2 Handler的postDelayed是精确的吗?
          • 14.3 子线程能更新UI吗?
        • 十五、子线程消息处理
          • 15.1 子线程中定义Handler
          • 15.2 子线程更新UI方式
          • 15.3 Handler内存泄漏
          • 15.4 消息Delay可靠性
          • 15.5 IdleHandler空闲机制
          • 15.6 Looper停止与App退出
        • 十六、总结
      • Activity启动原理
      • 四大组件原理分析
      • AMS与组件管理
      • View绑制与渲染
      • 事件分发机制
      • Surface渲染原理
      • 自定义View设计
      • WMS窗口管理
      • PMS与APK安装
      • 虚拟机与类加载
      • 内存管理与GC
      • 线程与并发编程
      • 性能优化与监控
      • 序列化与数据存储
      • 组件化与路由设计
      • 插件化与热修复
      • NDK开发实践
      • WebView核心设计
      • ADB常见使用操作
    • 智能硬件

  • iOS开发和进阶

  • Web开发和进阶

  • Linux应用开发

  • Apps
  • Android提升进阶
  • 专栏博客
杨充
2026-04-14
目录

Handler消息机制

# 03.Handler消息机制

# 目录介绍

  • 一、引言:为什么需要Handler
  • 二、Handler机制的整体架构
    • 2.1 四大核心组件
    • 2.2 消息流转的完整过程
  • 三、MessageQueue的数据结构与实现
    • 3.1 消息队列的链表结构
    • 3.2 消息入队(enqueueMessage)
    • 3.3 消息出队(next)
  • 四、Looper的工作原理
    • 4.1 Looper的创建与准备
    • 4.2 ThreadLocal的工作原理
    • 4.3 Looper.loop():消息循环
  • 五、Handler的消息发送与处理
    • 5.1 消息发送的多种方式
    • 5.2 消息分发优先级
    • 5.3 Handler与Looper的绑定关系
  • 六、Message的复用池机制
    • 6.1 Message的对象池实现
    • 6.2 复用池的设计思想
  • 七、Native层的MessageQueue
    • 7.1 Java层与Native层的关系
    • 7.2 NativeMessageQueue的创建
  • 八、epoll机制与线程休眠
    • 8.1 为什么使用epoll
    • 8.2 nativePollOnce的实现
    • 8.3 nativeWake的实现
  • 九、同步屏障与异步消息
    • 9.1 什么是同步屏障
    • 9.2 同步屏障在ViewRootImpl中的应用
    • 9.3 同步屏障的实现原理
  • 十、IdleHandler机制
    • 10.1 IdleHandler的定义与使用
    • 10.2 IdleHandler在系统中的应用
    • 10.3 IdleHandler的执行时机
  • 十一、HandlerThread与IntentService
    • 11.1 HandlerThread的实现
    • 11.2 IntentService的原理(已废弃但值得了解)
  • 十二、Handler导致的内存泄漏
    • 12.1 泄漏的根本原因
    • 12.2 解决方案
  • 十三、主线程Looper为什么不会ANR
    • 13.1 常见误解
    • 13.2 正确理解
    • 13.3 ANR的检测机制
  • 十四、面试高频问题与深度分析
    • 14.1 一个线程可以有几个Handler?几个Looper?几个MessageQueue?
    • 14.2 Handler的postDelayed是精确的吗?
    • 14.3 子线程能更新UI吗?
  • 十五、子线程消息处理
    • 15.1 子线程中定义Handler
    • 15.2 子线程更新UI方式
    • 15.3 Handler内存泄漏
    • 15.4 消息Delay可靠性
    • 15.5 IdleHandler空闲机制
    • 15.6 Looper停止与App退出
  • 十六、总结

# 一、引言:为什么需要Handler

Android的UI框架采用单线程模型——只有主线程(UI线程)可以更新界面。这个设计简化了UI操作的线程安全问题,但带来了一个挑战:耗时操作(网络请求、数据库读写、文件IO)不能在主线程执行(否则ANR),处理完结果后又需要切回主线程更新UI。

疑惑:为什么Android不采用多线程直接更新UI的方式?

答疑:如果允许多线程同时修改UI,就需要对所有UI操作加锁,这会带来两个严重问题:

  1. 性能下降:每次UI操作都需要获取锁,频繁的锁竞争会严重影响渲染性能
  2. 死锁风险:复杂的UI操作涉及多个View层级,多线程加锁容易产生死锁

Handler机制正是为了解决线程间通信问题而设计的。它提供了一种优雅的方式,让任意线程都能向目标线程的消息队列投递消息,由目标线程按序处理。


# 二、Handler机制整体架构

# 2.1 四大核心组件

Handler消息机制的四大组件:

┌──────────────────────────────────────────────────┐
│                    Thread                         │
│  ┌──────────┐    ┌──────────────┐                │
│  │ Handler   │───→│ MessageQueue │                │
│  │ 消息处理器 │    │ 消息队列      │                │
│  └──────────┘    │ ┌──────────┐ │  ┌──────────┐  │
│       ↑          │ │ Message  │ │  │  Looper   │  │
│       │          │ │ Message  │←│──│ 消息循环   │  │
│       │          │ │ Message  │ │  │           │  │
│  处理消息        │ └──────────┘ │  └──────────┘  │
│                  └──────────────┘                │
└──────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12

Message :消息载体,携带what、arg1、arg2、obj等数据

Handler :消息的发送者和处理者

MessageQueue:消息的存储容器(按时间排序的链表)

Looper :消息循环,不断从MessageQueue中取消息交给Handler处理

# 2.2 消息流转的完整过程

子线程                      主线程
   │                          │
   │ handler.sendMessage(msg) │
   │─────────────────────────→│ msg加入MessageQueue
   │                          │ (按msg.when排序插入链表)
   │                          │
   │                          │ Looper.loop()
   │                          │ ├── MessageQueue.next()
   │                          │ │   └── 取出队首消息
   │                          │ ├── msg.target.dispatchMessage(msg)
   │                          │ │   └── handler.handleMessage(msg)
   │                          │ └── msg.recycleUnchecked()
   │                          │
1
2
3
4
5
6
7
8
9
10
11
12
13

# 三、MessageQueue的数据结构与实现

# 3.1 消息队列的链表结构

MessageQueue并不是Java标准的Queue,而是一个按时间排序的单链表:

// MessageQueue.java
public final class MessageQueue {
    Message mMessages;  // 链表头指针(最早需要处理的消息)
    
    // 链表结构示意:
    // mMessages → msg1(when=100) → msg2(when=200) → msg3(when=500) → null
    //             ↑最先处理          ↑其次              ↑最后
}
1
2
3
4
5
6
7
8

# 3.2 消息入队(enqueueMessage)

boolean enqueueMessage(Message msg, long when) {
    synchronized (this) {
        msg.when = when;
        Message p = mMessages;  // 当前队列头
        boolean needWake;
        
        // 情况1:队列为空,或新消息的when最小(需要最先处理)
        if (p == null || when == 0 || when < p.when) {
            msg.next = p;
            mMessages = msg;  // 新消息成为队列头
            needWake = mBlocked;  // 如果线程在阻塞,需要唤醒
        } else {
            // 情况2:按时间顺序插入到链表的合适位置
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;  // 找到插入位置
                }
            }
            msg.next = p;
            prev.next = msg;  // 插入到prev和p之间
        }
        
        // 唤醒阻塞在nativePollOnce的线程
        if (needWake) {
            nativeWake(mPtr);  // 通过eventfd唤醒
        }
    }
    return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 3.3 消息出队(next)

Message next() {
    int pendingIdleHandlerCount = -1;
    int nextPollTimeoutMillis = 0;
    
    for (;;) {
        // 阻塞等待(核心!)
        // nextPollTimeoutMillis = -1:无限等待直到被唤醒
        // nextPollTimeoutMillis = 0:立即返回
        // nextPollTimeoutMillis > 0:等待指定时间
        nativePollOnce(ptr, nextPollTimeoutMillis);
        
        synchronized (this) {
            long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            
            // 如果队列头是同步屏障消息,跳过同步消息,找异步消息
            if (msg != null && msg.target == null) {
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            
            if (msg != null) {
                if (now < msg.when) {
                    // 还没到处理时间,计算需要等待的时间
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 取出消息
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    return msg;  // 返回消息给Looper
                }
            } else {
                nextPollTimeoutMillis = -1;  // 无消息,无限等待
            }
            
            // 处理IdleHandler(消息队列空闲时执行)
            if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            // ... 执行IdleHandler
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# 四、Looper的工作原理

# 4.1 Looper的创建与准备

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
    private static Looper sMainLooper;  // 主线程Looper
    
    final MessageQueue mQueue;
    final Thread mThread;
    
    // 每个线程只能有一个Looper(通过ThreadLocal保证)
    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(true));  // 创建并存入ThreadLocal
    }
    
    // 主线程专用
    public static void prepareMainLooper() {
        prepare(false);  // quitAllowed=false,主线程Looper不允许退出
        sMainLooper = myLooper();
    }
    
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 4.2 ThreadLocal的工作原理

ThreadLocal实现线程隔离的原理:

每个Thread对象内部都有一个ThreadLocalMap:
┌─────────────────────────────┐
│  Thread A                    │
│  threadLocals (ThreadLocalMap)│
│  ┌───────────┬──────┐       │
│  │ key=sThreadLocal │ value=LooperA │
│  └───────────┴──────┘       │
└─────────────────────────────┘

┌─────────────────────────────┐
│  Thread B                    │
│  threadLocals (ThreadLocalMap)│
│  ┌───────────┬──────┐       │
│  │ key=sThreadLocal │ value=LooperB │
│  └───────────┴──────┘       │
└─────────────────────────────┘

sThreadLocal.get() 实际是:
Thread.currentThread().threadLocals.get(sThreadLocal)
→ 不同线程获取到不同的Looper实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 4.3 Looper.loop():消息循环

public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;
    
    // 确保线程身份是正确的
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();
    
    for (;;) {  // 无限循环
        // 1. 从消息队列取消息(可能阻塞)
        Message msg = queue.next();
        if (msg == null) {
            return;  // MessageQueue.quit()被调用后返回null
        }
        
        // 2. 分发消息给对应的Handler
        // msg.target就是发送这条消息的Handler
        try {
            msg.target.dispatchMessage(msg);
        } finally {
            // Trace结束
        }
        
        // 3. 检查Binder身份是否被篡改
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            // 日志警告:消息处理过程中Binder身份被改变
        }
        
        // 4. 回收消息到复用池
        msg.recycleUnchecked();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 五、Handler的消息发送与处理

# 5.1 消息发送的多种方式

// 1. 发送Message
handler.sendMessage(msg);
handler.sendMessageDelayed(msg, delayMillis);
handler.sendMessageAtTime(msg, uptimeMillis);
handler.sendEmptyMessage(what);

// 2. 发送Runnable(内部也是封装为Message)
handler.post(runnable);
handler.postDelayed(runnable, delayMillis);
handler.postAtTime(runnable, uptimeMillis);

// 所有发送方式最终都汇聚到同一个入口:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;  // 将Handler自身设为消息的target
    msg.workSourceUid = ThreadLocalWorkSource.getUid();
    return queue.enqueueMessage(msg, uptimeMillis);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 5.2 消息分发优先级

public void dispatchMessage(Message msg) {
    // 优先级1:Message自带的callback(通过post(Runnable)发送的)
    if (msg.callback != null) {
        handleCallback(msg);  // 直接执行runnable.run()
        return;
    }
    
    // 优先级2:Handler构造时传入的全局callback
    if (mCallback != null) {
        if (mCallback.handleMessage(msg)) {
            return;  // callback返回true表示消息已处理
        }
    }
    
    // 优先级3:Handler子类重写的handleMessage
    handleMessage(msg);
}

// 分发优先级:
// msg.callback(Runnable)> Handler.Callback > handleMessage()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 5.3 Handler与Looper的绑定关系

// Handler必须绑定到一个Looper
public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;          // 绑定的Looper
    mQueue = looper.mQueue;    // 绑定的MessageQueue
    mCallback = callback;
    mAsynchronous = async;
}

// 如果不指定Looper,默认绑定当前线程的Looper
public Handler() {
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
}

// 这就是为什么在子线程创建Handler需要先调用Looper.prepare()
// 也是为什么主线程可以直接创建Handler(主线程已自动调用prepareMainLooper)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 六、Message的复用池机制

# 6.1 Message的对象池实现

public final class Message implements Parcelable {
    // 静态链表头:复用池
    private static Message sPool;
    private static int sPoolSize = 0;
    private static final int MAX_POOL_SIZE = 50;  // 最大缓存50个
    
    Message next;  // 链表指针(复用池和MessageQueue共用)
    
    // 从复用池获取Message
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0;  // 清除IN_USE标记
                sPoolSize--;
                return m;     // 复用已回收的Message
            }
        }
        return new Message();  // 池空则新建
    }
    
    // 回收Message到复用池
    void recycleUnchecked() {
        // 清理所有字段
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = UID_NONE;
        workSourceUid = UID_NONE;
        when = 0;
        target = null;
        callback = null;
        data = null;
        
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;  // 头插法加入复用池
                sPoolSize++;
            }
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 6.2 复用池的设计思想

Message复用池结构(链表实现的对象池):

sPool → [msg1] → [msg2] → [msg3] → null
         ↑ obtain()从头取出
         ↑ recycleUnchecked()从头插入

优势:
1. 减少GC压力:高频场景下避免大量创建/销毁Message对象
2. O(1)的获取和回收:链表头操作
3. 线程安全:synchronized保护

最佳实践:
// 推荐:从池中获取
Message msg = Message.obtain();
msg.what = MSG_UPDATE;
handler.sendMessage(msg);

// 不推荐:new创建(浪费对象)
Message msg = new Message();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 七、Native层的MessageQueue

# 7.1 Java层与Native层的关系

Handler消息机制并非纯Java实现,底层依赖Native层:

Java层                           Native层
┌──────────────────┐            ┌──────────────────┐
│ MessageQueue     │            │ NativeMessageQueue│
│ ├── mPtr ────────│───────────→│ ├── mLooper       │
│ ├── nativePollOnce│           │ │   (android::Looper)│
│ └── nativeWake   │            │ └── pollOnce()    │
└──────────────────┘            │     wake()        │
                                └──────────────────┘
                                         │
                                    ┌────┴────┐
                                    │  epoll  │
                                    │(Linux)  │
                                    └─────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13

# 7.2 NativeMessageQueue的创建

// frameworks/base/core/jni/android_os_MessageQueue.cpp
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

NativeMessageQueue::NativeMessageQueue() {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper(false);  // 创建Native Looper
        Looper::setForThread(mLooper);
    }
}

// Native Looper的构造
Looper::Looper(bool allowNonCallbacks) {
    mWakeEventFd.reset(eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC));
    // 创建eventfd用于唤醒
    
    rebuildEpollLocked();  // 创建epoll实例
}

void Looper::rebuildEpollLocked() {
    mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));
    // 创建epoll实例
    
    epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, &wakeEvent);
    // 将eventfd加入epoll监听
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 八、epoll机制与线程休眠

# 8.1 为什么使用epoll

Handler消息机制需要解决一个核心问题:当消息队列为空时,线程不能忙等待(浪费CPU),需要休眠;当有新消息到来时,需要能唤醒休眠的线程。

方案对比:
┌────────────┬──────────────────────────────────┐
│ 忙等待      │ while(!hasMessage) {} // CPU 100% │
│ sleep       │ Thread.sleep(100)   // 响应慢     │
│ wait/notify │ 需要额外的对象锁    // 可行但不够强大│
│ epoll       │ 事件驱动,精确唤醒  // Android的选择 │
└────────────┴──────────────────────────────────┘
1
2
3
4
5
6
7

epoll的优势:

  1. 可以同时监听多个文件描述符(不仅是eventfd)
  2. 支持超时等待(精确到毫秒)
  3. 高效的事件通知(O(1)复杂度)
  4. 可以同时处理Native层的事件(如InputEvent、VSync等)

# 8.2 nativePollOnce的实现

// 这是MessageQueue.next()中阻塞的底层实现
void NativeMessageQueue::pollOnce(int timeoutMillis) {
    mLooper->pollOnce(timeoutMillis);
}

int Looper::pollOnce(int timeoutMillis, ...) {
    for (;;) {
        // 先处理之前epoll_wait返回的Response
        while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            // 处理Native层的回调
        }
        
        result = pollInner(timeoutMillis);
        if (result != POLL_CALLBACK) {
            return result;
        }
    }
}

int Looper::pollInner(int timeoutMillis) {
    // 核心:epoll_wait等待事件
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
    // timeoutMillis = -1 → 无限等待
    // timeoutMillis = 0  → 立即返回
    // timeoutMillis > 0  → 等待指定毫秒
    
    for (int i = 0; i < eventCount; i++) {
        if (eventItems[i].data.fd == mWakeEventFd) {
            // 被nativeWake唤醒:读取eventfd清除唤醒标记
            awoken();
        } else {
            // 其他fd的事件(如InputChannel、VSync等)
            // 加入mResponses待处理
        }
    }
    
    // 处理Native层注册的MessageHandler消息
    while (mMessageEnvelopes.size() != 0) {
        // ... 处理Native消息
    }
    
    return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 8.3 nativeWake的实现

// 当新消息加入队列时,唤醒阻塞在epoll_wait的线程
void NativeMessageQueue::wake() {
    mLooper->wake();
}

void Looper::wake() {
    uint64_t inc = 1;
    // 向eventfd写入一个值,触发epoll_wait返回
    write(mWakeEventFd, &inc, sizeof(uint64_t));
}

// 流程:
// 线程A: handler.sendMessage(msg) 
//   → enqueueMessage() 
//   → nativeWake() 
//   → write(eventfd, 1)
//   → epoll_wait()返回
//   → 线程B从nativePollOnce()醒来
//   → MessageQueue.next()取到新消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 九、同步屏障与异步消息

# 9.1 什么是同步屏障

同步屏障(Sync Barrier)是一种特殊的消息,它可以让MessageQueue优先处理异步消息,跳过普通的同步消息。这是Android UI渲染流程的关键机制。

正常消息处理顺序:
msg1(sync) → msg2(sync) → msg3(async) → msg4(sync)
按时间顺序依次处理:1, 2, 3, 4

设置同步屏障后:
barrier → msg1(sync) → msg2(sync) → msg3(async) → msg4(sync)
跳过sync消息,优先处理async消息:3
移除屏障后恢复正常:1, 2, 4
1
2
3
4
5
6
7
8

# 9.2 同步屏障在ViewRootImpl中的应用

// ViewRootImpl.java — scheduleTraversals
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        
        // 1. 设置同步屏障(确保UI绘制消息优先处理)
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        
        // 2. 发送异步消息(绘制回调)
        mChoreographer.postCallback(
            Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        // 这个消息被标记为异步消息
    }
}

// 为什么需要同步屏障?
// VSync信号到来时,需要立即执行绘制操作
// 如果前面有很多同步消息在排队,绘制就会延迟,导致掉帧
// 同步屏障让绘制消息"插队",保证16ms内完成一帧渲染

void unscheduleTraversals() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        // 移除同步屏障
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 9.3 同步屏障的实现原理

// MessageQueue.java
public int postSyncBarrier() {
    synchronized (this) {
        final int token = mNextBarrierToken++;
        final Message msg = Message.obtain();
        msg.when = SystemClock.uptimeMillis();
        // 关键:msg.target = null!
        // 普通消息的target都是Handler,只有屏障消息target为null
        
        // 按时间顺序插入队列
        Message prev = null;
        Message p = mMessages;
        if (when != 0) {
            while (p != null && p.when <= when) {
                prev = p;
                p = p.next;
            }
        }
        if (prev != null) {
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        return token;
    }
}

// MessageQueue.next()中的屏障处理逻辑:
// if (msg != null && msg.target == null) {
//     // 遇到同步屏障,跳过同步消息,寻找异步消息
//     do {
//         prevMsg = msg;
//         msg = msg.next;
//     } while (msg != null && !msg.isAsynchronous());
// }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 十、IdleHandler机制

# 10.1 IdleHandler的定义与使用

// 当消息队列空闲时执行的回调
public static interface IdleHandler {
    // 返回true:保持注册,下次空闲时继续执行
    // 返回false:执行一次后自动移除
    boolean queueIdle();
}

// 注册IdleHandler
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
    @Override
    public boolean queueIdle() {
        // 消息队列空闲时执行
        // 适合做延迟初始化、数据预加载等
        doSomeLazyInit();
        return false;  // 只执行一次
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 10.2 IdleHandler在系统中的应用

系统使用IdleHandler的场景:

1. AMS — ActivityThread
   → 在消息队列空闲时执行GC(Runtime.getRuntime().gc())
   → 避免在业务处理时触发GC导致卡顿

2. Activity生命周期
   → onStop()的执行通过IdleHandler延迟
   → 只有消息队列空闲时才真正执行onStop
   → 这就是为什么onStop的调用时机不确定

3. LeakCanary(内存泄漏检测)
   → 在IdleHandler中检查弱引用是否被回收
   → 避免在业务繁忙时干扰正常运行

4. 应用启动优化
   → 将非关键初始化放在IdleHandler中
   → 保证首屏渲染不受影响
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 10.3 IdleHandler的执行时机

// MessageQueue.next()中IdleHandler的处理
Message next() {
    for (;;) {
        nativePollOnce(ptr, nextPollTimeoutMillis);
        
        synchronized (this) {
            // 取消息逻辑...
            
            // 当没有消息需要立即处理时,检查IdleHandler
            if (pendingIdleHandlerCount < 0 
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                mBlocked = true;
                continue;  // 没有IdleHandler,继续阻塞
            }
            
            // 拷贝IdleHandler数组(避免持有锁时执行回调)
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }
        
        // 在锁外执行IdleHandler
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            IdleHandler idler = mPendingIdleHandlers[i];
            boolean keep = idler.queueIdle();
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);  // 移除一次性IdleHandler
                }
            }
        }
        
        pendingIdleHandlerCount = 0;
        nextPollTimeoutMillis = 0;  // IdleHandler可能产生新消息,重新检查
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 十一、HandlerThread与IntentService

# 11.1 HandlerThread的实现

// HandlerThread:自带Looper的工作线程
public class HandlerThread extends Thread {
    Looper mLooper;
    
    @Override
    public void run() {
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();  // 通知getLooper()
        }
        onLooperPrepared();  // 钩子方法
        Looper.loop();       // 进入消息循环
    }
    
    // 线程安全地获取Looper(可能需要等待线程启动完成)
    public Looper getLooper() {
        synchronized (this) {
            while (mLooper == null) {
                wait();  // 等待run()中Looper创建完成
            }
        }
        return mLooper;
    }
}

// 使用方式:
HandlerThread handlerThread = new HandlerThread("worker");
handlerThread.start();
Handler workHandler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 在工作线程中处理消息
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 11.2 IntentService的原理(已废弃但值得了解)

// IntentService = HandlerThread + Service
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        
        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent) msg.obj);  // 在工作线程处理
            stopSelf(msg.arg1);  // 处理完自动停止
        }
    }
    
    @Override
    public void onCreate() {
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);  // 转发到工作线程
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 十二、Handler导致的内存泄漏

# 12.1 泄漏的根本原因

内存泄漏链路:

非静态内部类Handler → 隐式持有外部Activity引用
       ↓
Handler被Message.target引用
       ↓
Message在MessageQueue中等待处理
       ↓
MessageQueue被Looper引用
       ↓
主线程Looper是静态的,永远不会被回收
       ↓
GC Root → Looper → MessageQueue → Message → Handler → Activity(泄漏!)
1
2
3
4
5
6
7
8
9
10
11
// 泄漏代码示例
public class LeakyActivity extends Activity {
    // 非静态内部类:隐式持有LeakyActivity.this
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            updateUI();  // 引用了外部Activity的方法
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 发送一个10分钟后执行的延迟消息
        mHandler.sendEmptyMessageDelayed(0, 10 * 60 * 1000);
        // 如果Activity在10分钟内被销毁,Message仍在队列中
        // Message持有Handler → Handler持有Activity → Activity泄漏
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 12.2 解决方案

// 方案1:静态内部类 + 弱引用
public class SafeActivity extends Activity {
    private static class SafeHandler extends Handler {
        private final WeakReference<SafeActivity> mActivity;
        
        SafeHandler(SafeActivity activity) {
            mActivity = new WeakReference<>(activity);
        }
        
        @Override
        public void handleMessage(Message msg) {
            SafeActivity activity = mActivity.get();
            if (activity != null) {
                activity.updateUI();
            }
        }
    }
    
    private final SafeHandler mHandler = new SafeHandler(this);
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 方案2:销毁时移除所有消息
        mHandler.removeCallbacksAndMessages(null);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 十三、主线程Looper为什么不会ANR

# 13.1 常见误解

疑惑:主线程的Looper.loop()是一个死循环,为什么不会导致ANR?

答疑:这是一个非常常见的误解。首先需要明确ANR的定义:

ANR(Application Not Responding)的触发条件:
1. InputDispatching超时:5秒内未处理输入事件
2. Service超时:前台Service 20秒 / 后台Service 200秒
3. BroadcastReceiver超时:前台广播10秒 / 后台广播60秒
4. ContentProvider超时:10秒

ANR的本质是:某个消息(事件)在规定时间内没有被处理完

与Looper.loop()死循环无关!
1
2
3
4
5
6
7
8
9

# 13.2 正确理解

Looper.loop()的本质:

for (;;) {
    Message msg = queue.next();  // ← 没有消息时在这里阻塞(epoll_wait)
    msg.target.dispatchMessage(msg);  // ← 处理消息
}

当没有消息时:
→ 线程阻塞在epoll_wait,CPU不占用,不耗电
→ 这不是ANR,这是正常的等待状态
→ 类似于你等电话:没电话时你在休息,不是"没有响应"

当有消息时:
→ 线程被唤醒,处理消息
→ 如果处理时间太长(比如在handleMessage里做了耗时操作)
→ 导致后续的输入事件、Service超时消息等无法及时处理
→ 这才触发ANR

类比:
Looper.loop() = 一个快递员不停取件送件的循环
没有快递时 = 快递员休息(阻塞等待),不是ANR
有快递但送不过来 = 快递延迟(消息处理慢),这才可能ANR
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 13.3 ANR的检测机制

ANR检测原理(以InputDispatching为例):

1. InputDispatcher发送输入事件给App
2. 同时启动一个5秒定时器
3. App处理完事件后回复InputDispatcher
4. 如果5秒内没有回复 → ANR

时序图:
InputDispatcher              App主线程
    │                          │
    │ dispatch event           │
    │──────────────────────→│
    │ start 5s timer           │ handleMessage() 处理中...
    │                          │ 处理中...
    │                          │ 处理中...
    │ 5s timeout!             │ 还在处理中...
    │ → 触发ANR               │
    │                          │
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 十四、面试高频问题与深度分析

# 14.1 一个线程可以有几个Handler?几个Looper?几个MessageQueue?

一个线程:
- 可以有多个Handler(随便创建)
- 只能有一个Looper(ThreadLocal保证)
- 只能有一个MessageQueue(Looper构造时创建)

多个Handler共享同一个MessageQueue:
Handler1.sendMessage(msg1) → msg1.target = Handler1
Handler2.sendMessage(msg2) → msg2.target = Handler2
两个消息都在同一个MessageQueue中
Looper取出msg1 → 调用Handler1.dispatchMessage()
Looper取出msg2 → 调用Handler2.dispatchMessage()
1
2
3
4
5
6
7
8
9
10
11

# 14.2 Handler的postDelayed是精确的吗?

不是精确的。原因:

1. 消息处理延迟
   postDelayed(runnable, 1000)实际含义是:
   "至少1000ms后处理",不是"恰好1000ms时处理"
   
   如果队列前面的消息处理耗时500ms:
   实际延迟 = 1000ms + 前面消息处理时间 ≈ 1500ms

2. 时间基准
   使用的是SystemClock.uptimeMillis()(不计算休眠时间)
   不是System.currentTimeMillis()(墙钟时间)

3. 系统调度
   线程调度也有延迟(通常几毫秒到几十毫秒)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 14.3 子线程能更新UI吗?

严格来说:可以,但需要特定条件。

1. ViewRootImpl创建前(Activity.onResume之前)
   → 在onCreate中用子线程更新UI可能不报错
   → 因为checkThread()还未被建立

2. SurfaceView
   → 专门设计为可以在子线程绘制
   → 通过Surface的lockCanvas/unlockCanvasAndPost

3. 底层原理:
   ViewRootImpl.checkThread():
   void checkThread() {
       if (mThread != Thread.currentThread()) {
           throw new CalledFromWrongThreadException(
               "Only the original thread that created a view hierarchy "
               + "can touch its views.");
       }
   }
   // mThread = 创建ViewRootImpl的线程(通常是主线程)
   // 这不是"UI线程检查"而是"创建线程检查"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 十五、子线程消息处理

# 15.1 子线程中定义Handler

直接在子线程中创建Handler会报错:Can't create handler inside thread that has not called Looper.prepare()。

这是因为Handler的工作依赖于Looper,而Looper通过ThreadLocal与特定线程绑定。主线程在ActivityThread.main()中已经调用了Looper.prepareMainLooper(),而子线程默认没有Looper。

正确做法:在子线程中先调用Looper.prepare(),再创建Handler。注意在所有事情完成后应该调用quit方法终止消息循环,否则子线程会一直处于等待状态。

# 15.2 子线程更新UI方式

主要有以下方法:

  1. 主线程中定义Handler,子线程通过mHandler发送消息,主线程Handler的handleMessage更新UI
  2. Activity对象的runOnUiThread方法
  3. 创建Handler,传入getMainLooper,使用handler.post更新UI
  4. View.post(Runnable r)

这些方法的实现原理本质上都是通过Handler发送消息来实现的。

# 15.3 Handler内存泄漏

泄漏原因:通过内部类方式创建的mHandler会隐式持有外部类(Activity)引用。当执行post/send方法时,Message持有Handler引用,Handler持有Activity引用。如果Activity退出时消息队列中还有未处理的消息,就会导致Activity无法被回收。

解决方案:

  1. 在Activity销毁时移除消息:mHandler.removeCallbacksAndMessages(null)
  2. 使用静态内部类+弱引用:将Handler改为匿名静态内部类,对Activity使用WeakReference

# 15.4 消息Delay可靠性

Handler的postDelayed不是精确的延时,不靠谱的原因:

  • 发送的消息太多,Looper负载越高,任务越容易积压
  • 消息队列中有耗时消息处理,导致后面的消息延时
  • 对于时间精确度要求较高的场景,不应依赖Handler的delay

优化方案:

  • 消息精简,减少数量
  • 队列优化,重复消息过滤和互斥消息取消
  • 复用消息(Message.obtain())
  • 使用独享的Looper(HandlerThread)

# 15.5 IdleHandler空闲机制

IdleHandler是在消息队列空闲时执行的回调,适合处理不紧急的任务:

MessageQueue.IdleHandler idleHandler = new MessageQueue.IdleHandler() {
    @Override
    public boolean queueIdle() {
        // 返回false表示执行一次后移除,返回true表示保留
        return false;
    }
};
Looper.myQueue().addIdleHandler(idleHandler);
1
2
3
4
5
6
7
8

# 15.6 Looper停止与App退出

调用Looper.getMainLooper().quit()或quitSafely()会导致App崩溃退出。

  • quit():清空MessageQueue中的所有消息(包括延迟和非延迟消息)
  • quitSafely():只清空延迟消息,非延迟消息会被派发处理后再退出

无论调用哪个方法,Looper退出后都不再接收新消息,通过Handler发送消息会返回false。

quit与quitSafely的源码级对比:

MessageQueue.quit(boolean safe) {
    if (safe) {
        // quitSafely:移除所有when > now的延迟消息
        removeAllFutureMessagesLocked();
        // 已到时间的消息正常处理完毕后退出
    } else {
        // quit:移除所有消息
        removeAllMessagesLocked();
    }
    mQuitting = true;
    nativeWake(mPtr);  // 唤醒阻塞中的next()
}

MessageQueue.next() {
    // ...
    if (mQuitting) {
        dispose();
        return null;  // 返回null给Looper
    }
}

Looper.loop() {
    Message msg = queue.next();
    if (msg == null) {
        return;  // next返回null → 退出循环
    }
}

主线程Looper退出的后果:
  主线程的消息循环终止
  → 后续的生命周期回调无法执行
  → InputDispatcher发送的事件无人处理
  → 5秒后触发ANR
  → 最终进程被kill
  
子线程Looper退出是正常操作:
  HandlerThread.quitSafely()
  → 处理完当前消息后退出
  → 线程结束运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

# 十六、总结

Handler消息机制是Android最核心的线程通信框架:

Handler知识图谱:

核心组件
├── Message(消息载体) → 对象池复用
├── MessageQueue(消息队列) → 时间排序链表
├── Looper(消息循环) → ThreadLocal + 死循环
└── Handler(收发处理) → 发送 + 分发 + 处理

底层原理
├── Native层 → NativeMessageQueue + android::Looper
├── epoll机制 → 高效的事件等待与唤醒
├── eventfd → 线程间唤醒信号
└── 同步屏障 → 异步消息优先处理(UI渲染保障)

高级特性
├── IdleHandler → 空闲时执行
├── 同步屏障 → UI渲染优先级
├── HandlerThread → 自带Looper的工作线程
└── Message复用池 → 减少GC压力

常见问题
├── 内存泄漏 → 静态内部类 + 弱引用
├── ANR → 消息处理超时,不是Looper死循环
└── 精度问题 → postDelayed不精确
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

理解Handler机制,是理解Android UI渲染、事件分发、组件生命周期管理等高级主题的基础。它贯穿了Android应用开发的方方面面。

上次更新: 2026/06/10, 11:13:41
Binder通信原理
Activity启动原理

← Binder通信原理 Activity启动原理→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式