You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Handler构造方法中Looper的作用?线程执行差异引发的疑问

解惑:Handler中Looper如何决定handleMessage的执行线程

兄弟,你的观察完全准确!Looper确实直接决定了handleMessage()的执行线程,咱们结合你的两段代码和Handler的核心运行逻辑来掰扯清楚~

先拆解你的两段代码差异

snippet1:绑定主线程Looper的情况

mThread = new Thread(){
    @Override
    public void run() {
        Log.d(tag, "thread 1 current thread:" + Thread.currentThread());
        //if(null == Looper.myLooper()) {// This is redundant.
        //Looper.prepare();
        //}
        Log.d(tag, "thread 2 current thread:" + Thread.currentThread());
        mHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                Log.d(tag, "thread 3 current thread:" + Thread.currentThread());
            }
        };
        mHandler.sendEmptyMessage(0);
        //Looper.loop(); // This is redundant since mHandler has a mainLooper, and loop in main thread.
    }
};
  • 这里创建Handler时主动传入了Looper.getMainLooper(),这个Looper是主线程专属的——APP启动时系统就已经在主线程完成了Looper.prepare()和Looper.loop(),主线程的消息循环一直处于运行状态
  • 调用mHandler.sendEmptyMessage(0)时,这条消息会被投递到**主线程的消息队列(MessageQueue)**中
  • 主线程的Looper一直在循环取出队列里的消息,随后调用对应Handler的handleMessage()方法,所以这个处理过程自然在主线程执行,也就是你看到的"thread 3"输出主线程
  • 子线程里的Looper.prepare()和Looper.loop()确实多余,因为咱们根本没用到这个子线程的Looper,Handler绑定的是主线程的Looper

snippet2:绑定子线程Looper的情况

mThread = new Thread(){
    @Override
    public void run() {
        Log.d(tag, "thread 1 current thread:" + Thread.currentThread());
        if(null == Looper.myLooper()) {
            Looper.prepare();
        }
        Log.d(tag, "thread 2 current thread:" + Thread.currentThread());
        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                Log.d(tag, "thread 3 current thread:" + Thread.currentThread());
            }
        };
        mHandler.sendEmptyMessage(0);
        Looper.loop();
    }
};
  • Looper.prepare()的作用是在当前子线程中创建一个Looper实例,同时生成对应的MessageQueue,并且把这个Looper和当前线程绑定(存在ThreadLocal里)
  • 无参构造的Handler会自动获取当前线程的Looper(也就是刚在子线程创建的那个),完成绑定
  • sendEmptyMessage(0)把消息投递到子线程的MessageQueue中
  • Looper.loop()启动子线程的消息循环:这个循环会在子线程里不断取出队列中的消息,调用Handler的handleMessage()处理,所以此时handleMessage()就在子线程执行,输出子线程

核心逻辑:Looper和线程的绑定关系

Looper的本质是线程绑定的消息循环器,核心规则如下:

  1. 每个Looper实例在创建时(Looper.prepare()),会被存储到当前线程的ThreadLocal变量中,和线程形成强绑定
  2. Handler在创建时必须绑定一个Looper(要么主动传入,要么自动取当前线程的Looper)
  3. 当Looper调用loop()启动循环时,是在自己绑定的线程中持续从MessageQueue取消息,然后调用消息对应的Handler的dispatchMessage()方法,最终走到handleMessage()——这个整个调用链都在Looper所在的线程里,所以handleMessage()的执行线程就是Looper绑定的线程

如果你再去看源码,可以重点看这几个点:

  • Handler的无参构造方法里,会调用Looper.myLooper()获取当前线程的Looper
  • Looper.loop()方法中,取出消息后会执行msg.target.dispatchMessage(msg),而dispatchMessage()最终会触发handleMessage(),这个过程完全在loop()运行的线程(也就是Looper绑定的线程)中执行

内容的提问来源于stack exchange,提问作者twlkyao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:44:23