在这篇文章开始前,我们先总结一下前两篇文章中关于Handler, Looper和MessageQueue等的一些关键点:
0)在线程中创建Handler之前,必须先调用Looper.prepare(), 创建一个线程局部变量Looper,然后调用Looper.loop() 进入轮循。
1)当Handler创建之后,就可以调用Handler的sendMessageAtTime方法发送消息,而实际上是调用MessageQueue的enqueueMessage方法,将对应的消息放入消息队列。
2)每一个线程都只有一个Looper,这个Looper负责对MessageQueue进行轮循,当获取到Message,就调用handler.dispatchMessage进行分发。
从上面这三点,我们就可以大概地看出Handler的使用流程了。
今天我们就先从消息开始的地方讲起,就是Handler的 enqueueMessage 方法了,代码如下:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
1)将msg.target 设置成当前Handler对象
2)调用MessageQueue的enqueueMessage方法
所以,其实就是在这里,将Message对象放到消息队列中去的。
说到MessageQueue,我们首先要明白这个消息队列其实是一个链表的结构,一个串一个的。
而其队列的初始化并不是在 java层做的,而是在JNI层利用C++实现的。
我们可以看看其定义的几个native方法,如下:
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native static void nativePollOnce(long ptr, int timeoutMillis);
private native static void nativeWake(long ptr);
private native static boolean nativeIsIdling(long ptr);
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
在这里,我们并不进入其在JNI层的代码,水太深了。
我们还是从Java层来看吧。在MessageEnqueue的 enqueueMesage方法中,主要的代码如下:
synchronized (this) {
...
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;
}
...
}
既然消息已经放到队列中去了,那么下一步就是在Looper的轮循操作中去获取消息,然后将消息进行分发。我们可以在Looper 的loop方法中看到其调用了MessageQueue的next方法。
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);
Message next() {
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// We can assume mPtr != 0 because the loop is obviously still running.
// The looper will not call this method after the loop quits.
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (false) Log.v("MessageQueue", "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
1)是一个 for(;;)循环
2)只有当获取 message的时候或者mQuitting为true的时候才会跳出循环。
3)在获取消息的时候,会根据 Message.when 字段来进行判断
从以上几点,我们就可以大概了解为什么说在 loop方法中,next方法有可能会阻塞,因为它就是一个无限的轮循操作呀。
好吧,到这里之后,我们大概知道了以下两件事情:
1)在Handler的sendMessageAtTime方法调用MessageQueue的 enqueueMessage方法,将消息放入队列。
2)在Looper的looop方法,调用MessageQueue的next方法,将消息取出队列。
接下来第三步,很显然,就是调用handler的dispatchMessage方法了,如下:
msg.target.dispatchMessage(msg);
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
1)msg.callback
2) mCallback
3 ) handleMessage
首先, msg.callback是什么?
在Message类中,我们可以看到
Runnable callback;
还有其构造函数:
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
所以在dispatchMessage中,首先就是判断是否有对Message设置了Runnable的callback,如果有,就执行这个callback方法,如下:
private static void handleCallback(Message message) {
message.callback.run();
}
public interface Callback {
public boolean handleMessage(Message msg);
}
而一般情况下,只有我们想去继承Handler类,实现自定义的Handler的时候,我们才会去实现这个接口,而当此接口返回true的时候,Handler默认的handleMessage方法就不会再被调用了。反之,则依然会调用。
最后,就是我们最普通的handleMessage方法了,也就是我们在实现一个最普通的handler的时候所实现的方法了。
同样,没有例子怎么可以呢,请看代码:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId());
switch (msg.what) {
case MSG_ID_1:
Log.v("Test", "Toast called from Handler.sendMessage()");
break;
case MSG_ID_2:
String str = (String) msg.obj;
Log.v("Test", str);
break;
}
}
};
Looper.loop();
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId());
LooperThread looperThread = new LooperThread();
looperThread.start();
while(looperThread.mHandler == null){
}
Message message = Message.obtain(looperThread.mHandler, new Runnable() {
@Override
public void run() {
Log.v("Test", "Message.callack()");
}
});
message.what = MSG_ID_1;
message.sendToTarget();
looperThread.mHandler.post(new Runnable() {
@Override
public void run() {
Log.v("Test", "Handler.callack()");
}
});
}
10-28 11:27:49.328: V/Test(22009): Id of MainThread : 1
10-28 11:27:49.328: V/Test(22009): Message.callack()
10-28 11:27:49.328: V/Test(22009): Handler.callack()