Handler的创建Message的处理与Looper的作用——源码分析
Posted Greyson_Guo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Handler的创建Message的处理与Looper的作用——源码分析相关的知识,希望对你有一定的参考价值。
分析源码,总结小过程(源码只打印出重要部分):一般Hanlder的创建:
//Handler的部分构造方法
public Handler()
this(null, false);
public Handler(Callback callback, boolean async)
mLooper = Looper.myLooper();
if (mLooper == null)
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
Handler中有几个重要的全局变量:mLooper、mQueue、mCallback,分别为此Handler所在的线程的Looper对象、消息队列、还有Handler的回调接口(此接口有handleMessage()方法,实现此接口可以替代,必须匿名内部类重写Handler的handleMessage()方法的情况)。
在以上源码中可看出创建Handler的时候会调用Looper的静态方法myLooper():
public static @Nullable Looper myLooper()
return sThreadLocal.get();
此方法会去访问Looper对象中的属性ThreadLocal对象的get()方法:
public T get()
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();//获取当前线程
Values values = values(currentThread);//获取线程对应的ThreadLocal.Values对象
return (T) values.getAfterMiss(this);//获取Values中的Looper对象
即它会去访问当前线程中的属性ThreadLocal.Values对象,对象中维护了一个一维Object数组,数组顺序交替保存了ThreadLocal和Looper对象,所以可以从整体上看待ThreadLocal,把它当作一个Map对象(Java的ThreadLocal的确维护着一个Map对象),里面存着以ThreadLocal为key,以Looper对象为value的键-值对。最后通过Values的getAfterMiss()方法返回当前线程对应的Looper对象。
总结, Handler在哪个线程中创建,它都会与当前线程的Looper绑定在一起,操作的消息队列也是当前线程与其Looper所维护的消息队列。
Looper的创建: 1)首先我们来看一下官方API对Looper的介绍: Looper用来在线程中执行一个消息队列(原文是“message loop”在此翻译为消息队列会比较好译)。线程默认情况都不会有与之关联的消息队列。如果在线程调用prepare(),那么会创建一个Looper与该线程关联,线程就拥有了自己的消息队列。并且必须调用loop()方法到执行消息队列直到队列被停止。 一般用户与消息队列的交互都是通过Handler类,以下是一个典型的例子:
class LooperThread extends Thread
public Handler mHandler;
public void run()
Looper.prepare();
mHandler = new Handler()
public void handleMessage(Message msg)
// process incoming messages here
;
Looper.loop();
源码前的分析:当线程有了自己的Looper(也拥有了消息队列),在它的代码就可以创建Handler来与用户交互,即Handler在哪个线程创建,它就属于哪个线程,它发送的消息Message也会加入它所属的线程的消息队列中。如果线程没有Looper就创建Handler类对象会产生"Can't create handler inside thread that has not called Looper.prepare()"异常。自己在线程中维护一个Looper要注意可能必须调用quit()方法来关闭Looper。
2)再来看源码。Looper的构造方法和一些重要的全局变量:
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed)
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
新建消息队列并保存当前线程到全局变量mThread中。因为此方法是私有,所以只能在内部实例化,这就用到了我们常见的Looper静态方法prepare():
public static void prepare()
prepare(true);
private static void prepare(boolean quitAllowed)
if (sThreadLocal.get() != null)
throw new RuntimeException("Only one Looper may be created per thread");
sThreadLocal.set(new Looper(quitAllowed));
由源码可知,创建Looper时会先尝试从ThreadLocal对象中获取,如果ThreadLocal中还没保存Looper,就会新建一个Looper对象并保存到ThreadLocal(其中的Thread.Values的数组中)中,
这就保证了一个线程中只有一个Looper。
当线程调用了prepare()方法,Looper会将当前线程的对象保存到mThread变量中,即绑定了当前创建它的线程。线程有了自己的Looper和MessageQueue后,必须调用Looper.loop()方法(源码请看“Handler的消息处理”),让消息队列开始运转。
Looper还有个重要的方法(对系统而言):
public static void prepareMainLooper()
prepare(false);
synchronized (Looper.class)
if (sMainLooper != null)
throw new IllegalStateException("The main Looper has already been prepared.");
sMainLooper = myLooper();
它将当前线程的Looper设置为整个应用的主要Looper(他属于UI线程)。应用的主要Looper是由安卓环境创建的,所以开发者不需要自己去调用他。
Handler的消息处理:
public final boolean sendMessage(Message msg)
return sendMessageDelayed(msg, 0);
public final boolean sendMessageDelayed(Message msg, long delayMillis)
if (delayMillis < 0)
delayMillis = 0;
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
MessageQueue queue = mQueue;
if (queue == null)
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
return enqueueMessage(queue, msg, uptimeMillis);
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis)
msg.target = this;//将消息执行完成要回调的handleMessage()方法所属的对象设置为当前对象
if (mAsynchronous)
msg.setAsynchronous(true);
return queue.enqueueMessage(msg, uptimeMillis);
平时我们调用的sendMessage(Message msg)方法经过一些参数的判断和处理后,最终到了enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) 方法中来实现功能;在这里,将我们想发送的Message对象的target设为当前Handler对象,这就是为什么MessageQueue中有很多Message,但执行时可以回调到正确的Handler对象的原因。最后用了MessageQueue的enqueueMessage(msg, uptimeMillis)方法将消息推入队列中。
Looper.prepare()调用后,都必须调用Looper.loop()方法以运转消息队列,这样Handler发的消息才可以被处理:
public static void loop()
final Looper me = myLooper();
if (me == null)
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
final MessageQueue queue = me.mQueue;
//一直循环获取消息对象
for (;;)
Message msg = queue.next(); // 可能会堵塞
if (msg == null)
// 没有消息,意味着消息队列正在退出
return;
msg.target.dispatchMessage(msg);//派遣任务,让Handler处理消息内容
msg.recycleUnchecked();//回收消息对象,标为“非在用”状态
从上面的源码可以看出,消息队列一直无止境地循环获取消息,而消息的处理则是Message对象中的target,处理任务又回到了Handler中:
public void dispatchMessage(Message msg)
if (msg.callback != null) //如果有线程任务,则执行线程
handleCallback(msg);
else
if (mCallback != null)
if (mCallback.handleMessage(msg))
return;
handleMessage(msg);
private static void handleCallback(Message message)
message.callback.run();
Handler会优先判断是否有实现了Handler.CallBack接口的类对象mCallback,如果没有直接回调Handler的handleMessage()方法;有则回调该对象的handleMessage()方法,并且判断消息是否继续传递到Handler的handleMessage()方法。
以上是关于Handler的创建Message的处理与Looper的作用——源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Handler的创建Message的处理与Looper的作用——源码分析
android消息处理机制之2handler与looper,MessageQueue:的关系
Android Handler消息机制03-Message源码学习
Handler类和Handler,Loop,MessageQueue的工作原理