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的本质是线程绑定的消息循环器,核心规则如下:
- 每个Looper实例在创建时(
Looper.prepare()),会被存储到当前线程的ThreadLocal变量中,和线程形成强绑定 - Handler在创建时必须绑定一个Looper(要么主动传入,要么自动取当前线程的Looper)
- 当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
相关产品推荐
相关产品推荐

