android Looper、Handler和MessageQueue关系
android 消息框架可以在线程间传递消息,android中最广泛的应用场景就是子线程向UI线程发送更新UI的消息。
Looper:用来进行消息循环,不停的从MessageQueue中取消息。
Handler:向MessageQueue发送消息,并处理Looper传递来的消息。
Message:消息载体。
MessageQueue:消息队列的持有者,消息并不是直接存放到MessageQueue。
这是一个比较典型的应用事例。
下面我们围绕这个事例分析一下:
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.prepare()方法,prepare()内部调用了带有参数的prepare(boolean)方法,参数主要是控制消息队列的特殊情况(队列中无消息时该如何处理);参数为true且无消息时,退出消息队列;参数为false且无消息时,消息队列进入阻塞状态,仅当消息队列有消息时,消息队列会被唤醒。
其中sThreadLocal变量是ThreadLocal类型,ThreadLocal主要功能是保存线程本地变量;它类似于HashMap,以键值对的方式存储,键为当前线程。想详细了解的话可以看看这篇博文http://www.cnblogs.com/dolphin0520/p/3920407.html
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,Looper创建完毕后就可以从MessageQueue取消息了;Looper.loop()后就进入消息循环了。下面的方法主要是从消息队列取消息,然后处理消息;消息的最终消费者是Handler。
public static void loop() {
final Looper me = myLooper();
if (me == null) { //没有创建Looper
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(); // 可能会阻塞
if (msg == null) {
//没有消息时,表示消息队列正准备退出
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();
}
}
那么消息时如何传递到相应的Handler呢?
当我们调用Handler.sendMessage(Message)时,Message对象会保存Handler对象到target中;处理信息时调用target的dispathMessage()方法,最终会执行Handler的handleMessage()方法。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
那么消息时如何传递到相应的Handler呢?
当我们调用Handler.sendMessage(Message)时,Message对象会保存Handler对象到自身,当要处理信息时,便从自身取出Handler