Handler, Looper, Message三者之间的关系基本上是面试官必问问题之一,那今天让我们从源码的角度来解读一下它们之间的关系
Handler 构造
//主线程创建Handler
Handler handler = new Handler();
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
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 = Looper.myLooper();
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
通过myLooper方法得到一个Looper,sThreadLocal存放的Looper,是主线程main方法中创建的
mQueue = mLooper.mQueue;
mQueue 为消息队列,是从Looper中获取,接下来看它发送消息的逻辑
Handler 发送消息
handler.sendMessage(new Message());
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;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
上面代码经过层层调用,最终把消息插入到MessageQueue 队列中(queue队列就是在构造方法中从Looper得到的 )
//把Hander对象赋值给消息的target 的属性
msg.target = this;
从构造方法和发送消息可以得出:首先得到主线程创建的Looper对象,然后得到Looper对象中的MessageQueue,然后发送消息到MessageQueue队列当中,插入消息队列以后要如何处理呢?我们来看看Looper的一些方法
Looper prepare方法
主线程在创建的时候会调用Looper的prepare和loop方法,那prepare方法里面干了什么呢?
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对象然后存放到sThreadLocal中,而Handler对象中的Looper就是从sThreadLocal中获取的,接下来看看loop方法
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;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
首先得到looper里的消息队列,然后循环从消息队列里取message,最后调用message里target的dispatchMessage方法,target就是发送消息的Handler对象
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
主要看handleMessage方法这行代码,handleMessage需要我们自己去实现,下面这行代码什么时候会调用呢?
if (msg.callback != null) {
handleCallback(msg);
}
这段代码是什么意思呢?这里涉及到发送消息的另外一种方式,我们有时候为了简单会这样调用
handler.post(new Runnable() {
@Override
public void run() {
}
})
//调用的post方法
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
从getPostMessage方法中可以看到,首先从消息池中得到消息对象,然后把我们创建的Runnable对象赋值给消息的callback属性,我们回过头看看上面的判断代码,判断callback是否为空,不为空调用handleCallback方法
private static void handleCallback(Message message) {
message.callback.run();
}
方法里面就是回调callback的run方法,run方法就是我们自己的业务逻辑代码
总结
到此三者之间的关系已经分析完毕,主线程在创建时创建Looper对象,在Looper构造方法中创建消息队列MessageQueue,调用Looper的loop方法启动消息循环;然后Handler在创建时从sThreadLocal中取主线程Looper对象中MessageQueue,发送消息插入到消息队列,loop循环取出消息,调用Handler的handleMessage方法或callback回调方法完成消息处理,所以Handler对象必须关联一个Looper对象,在子线程中使用Handler必须要调用Looper的prepare和loop方法,因为它需要Looper的消息队列和消息循环处理,而主线程在创建时已经创建了Looper对象,并启动了Looper循环,所以在主线程中使用Handler不需要调用这2个方法。