源码分析Android Handler是如何实现线程间通信的
Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的。开发者从一开始就被告知必须在主线程中进行UI操作。但Handler是如何实现线程间通信的呢?本文将从源码中分析Handler的消息通信机制。
0x00 Handler使用
首先看看我们平时是如何使用的Handler
的。先看看以下代码
//定义Handler
Handler mHandler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case UPDATE_UI:
updateUI(msg);
break;
}
}
};
class MyThread extends Thread{
public void run(){
//do same work!
...
//send message
Message msg = mHandler.obtainMessage(UPDATE_UI);
mHandler.sendMessage(msg);
}
}
private void updateUI(Message msg){
//update UI
}
在子线程中sendMessage(Message)
发送消息,然后在Handler的handleMessage(Message)
接收消息,执行更新UI操作。那么Handler
是如何把消息从MyThread
传递到MainThread
中来呢?我们从sendMessage()
开始慢慢揭开它的面纱。
0x01 sendMessage(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);
}
我们发现调用sendMessage()
方法最后都走到enqueueMessage()
这个方法,一开始就把当前Handler
实例赋给了Message.target
的属性里面,后面可以知道这个target
是用来执行处理函数回调的。
enqueueMessage
方法是把Message
信息放入到一个MessageQueue
的队列中。顾名思义MessageQueue
就是消息队列。从sendMessageAtTime()
方法知道这个MessageQueue
是Handler
中的一个成员。它是在Handler
的构造函数中通过Loopger
对象来初始化的。
0x02 Handler构造函数
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
的时候,同时也创建了Looper
实例和MessageQueue
引用(MessageQueue
对象其实是在Looper
中构造的)。Looper
是何物呢?简单地说就是消息循环,这个我们稍后会分析。
0x03 enqueueMessage(MessageQueue)
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
//这里把消息插入到队列中
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
在MessageQueue
中可以看到这个入列方法中有一个for
循环就是把当前的需要处理Message
放到队列的合适位置。因为需要处理的Message
对象都有一个开始处理的时间when
,这个队列是按照when
排序的。
至此,Handler
调用sendMessage()
方法后就把Message
消息通过enqueueMessage()
插入MessageQueue
队列中。
而这个MessageQueue
是在Looper
中维护的。
0x04 prepare()创建Looper
在0x02中我们知道创建Handler
时就使用静态方法Looper.myLooper()
得到当前线程的Looper
对象。
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
sThreadLocal
是一个ThreadLocal
类型的静态变量。什么时候会把Looper
对象放在sThreadLocal
中呢?通过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
在构造函数中创建MessageQueue
对象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
调用prepare()
方法将一个Looper
对象放在了静态的ThreadLocal
对象中。这个是一个与线程绑定的对象,且在内存中仅保存了一份引用。
使用ThreadLocal
对象这一点非常巧妙,也非常重要,这是线程间通信的基础。即在线程中调用prepare()
时就在该线程中绑定了Looper
对象,而Looper
对象中拥有MessageQueue
引用。所以每个线程都有一个消息队列。
这样Handler
、Looper
、MessageQueue
这几个类关系大概就可以画出来了。
0x05 启动循环loop()
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the 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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
//执行处理消息的回调
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
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();
}
}
loop()
方法中有一个无限循环,不停地读取调用MessageQueue
的next()
方法。当next()
没有返回时就阻塞在这里。当获取到MessageQueue
中的消息时,就执行了处理消息的回调函数msg.target.dispatchMessage(msg)
。
前面0x01分析我们知道msg.target
是在Handler
中的enqueueMessage()
进行赋值,即它指向当前的Handler
实例。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
执行msg.target.dispatchMessage(msg)
后便走到了以下流程
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这里就是回调handleMessage(msg)
函数处理消息的地方。Handler
负责将Message
入列,Looper
则负责循环从MessageQueue
中取出需要处理的Message
并交由Handler来处理。
0x06 启动主线程的消息循环
我们知道通过静态方法Looper.prepare()
创建了绑定当前线程的Looper
对象,