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开发至关重要。

核心要点

  1. 4个组件:Message、MessageQueue、Looper、Handler
  2. 工作流程:发送→入队→循环→分发→处理
  3. 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 #消息机制 #源码分析

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐