2) Looper.loop,进入消息循环
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
// 这里的 me 即为所在线程中的存储在本地线程局部变量中的 Looper 对象
Looper me = myLooper();
// 取出 looper 中的消息队列,也就是在 prepare() 中创建的队列
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();
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
// No target is a magic identifier for the quit message.
return;
}
long wallStart = 0;
long threadStart = 0;
... .. .
// 实际的消息分派在这里
// 从第一节的图中可以看到 Message.target 为 Handler
msg.target.dispatchMessage(msg);
... ...
// 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.recycle();
}
}
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
其实从 Looper 的 prepare 和 loop 两个关键方法已经引出了 Handler, MessageQueue, Message,结合图可以简单的说清他们之间的关系:
- Looper 创建了 MQ;
- MQ 使用单链表结构存储了所有 Message;
- 每个 Message 又会关联一个处理此消息的 Handler;
- 而这个 Handler 就是最终用来处理此消息的;
当然,里面也还有很多细节的,我们再从 Looper.loop() 方法中的关键调用 msg.target.dispatchMessage(msg); 的消息分派开始深入了解一下 Handler。
Handler
我结合自己的问题更深入了解 Handler 的:
- 从图中可以看到 Handler 中也有一个 mQueue,这个 mQueue 和 Looper 中创建的队列有什么不同么?
在找这个答案的同时,也正好是了解一下 Handler 的三种构造方式:
/**
* Default constructor associates this handler with the queue for the
* current thread.
*
* If there isn't one, this handler won't be able to receive messages.
*/
public Handler() {
... ...
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 = null;
}
/**
* Constructor associates this handler with the queue for the
* current thread and takes a callback interface in which you can handle
* messages.
*/
public Handler(Callback callback) {
... ...
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;
}
/**
* Use the provided queue instead of the default one.
*/
public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = null;
}
代码很清晰,这里的 mQueue 其实就是 Handler 对象所在线程的 Looper 的 MQ,两者是同一个 MQ。在第二个构造方式中,又扯入了一个 mCallback 成员,根据名称应该是 消息的回调,下面在分析 dispatch 时会看到;
- Looper.loop() 中的 queue.next() 的消息来自于哪里,也就是消息怎么入队的?
最简单的方式应该是通过 Looper.getQueue() 得到 MessageQueue 对象,再通过 MessageQueue 的 enqueueMessage() 方法将消息入队。可惜,不行啊,Looper.getQueue() 为 @Hide 的,上层应用无法访问的。可以通过 Handler 的一些辅助方法来访问:
// 将消息加入 MQ 尾部
public final boolean sendMessage(Message msg)
// 将消息加入 MQ 头部,用于放置优先级较高的消息
public final boolean sendMessageAtFrontOfQueue(Message msg)
// 移除消息码为 what 的消息
public final void removeMessages(int what)
// 创建一个消息码为 what 的消息
public final Message obtainMessage(int what)
// 查看 MQ 中是否有消息码为 what 的消息
public final boolean hasMessages(int what)
上面只列出了一部分 Handler 提供的消息访问相关的方法,更多的如下图:
下面为消息入队(sendMessage)的源码过程:
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
{
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
// 这里将该消息的 target 设置为本 handler
msg.target = this;
sent = queue.enqueueMessage(msg, uptimeMillis);
}
... ...
return sent;
}
其中,参数 uptimeMillis 为发送消息时的绝对时间,一般应用都是通过调用 sendMessage(Message msg)方法,而该方法会调用 sendMessage(Message msg, long delayMillis),在该方法中又会设置 uptimeMillis 参数,并调用上面的方法实现。
这里的主要动作就是设置 Message 的 target 为调用的 Handler,并将消息入队。
- Handler 的消息分派机制;
public void dispatchMessage(Message msg) {
// 如果 Message 本身设置了 callback,则交给 Message 自己的 callback
if (msg.callback != null) {
handleCallback(msg);
} else {
// 如果是 Handler 设置了 callback,则交给 handler 的 callback
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果都没有设置,则交给 handleMessage
handleMessage(msg);
}
}
可以看到这里的消息分派的机制和流程是:
首先判断被分派的消息本身是否设置了 callback,如果设置了,则交给该 callback,分派结束;
如果 Message 没有设置 callback,则判断 Handler 本身有没有设置 callback,如果设置,则交给 Handler 的 callback,分派结束;
如果 Handler 也没有设置,则调用 Handler.handleMessage(Message),而该 handleMessage 就是应用需要实现的处理消息的地方了。
转载于:https://blog.51cto.com/quietmadman/1282293