原理
个人的一点理解
本质上,Handler的使用就是从一个MessageQueue中不断取出其所绑定的Message,随后调用其本身的handleMessage(...)
方法,但是使用Handler有三个基本要点:
1.每个线程线程只有一个Looper,而Looper其实就是引用了一个MessageQueue
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和当前线程相关绑定起来
}
2.Looper.loop()
包含了一个死循环for(;;)
,在该循环中不断对当前线程唯一的Looper所引用的MessageQueeue执行出栈或者出队列操作,并通过message.target
驱使每一条信息所绑定的Handler对该条message进行处理。
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;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg); //无论是调用post()还是setTarget(),最后都会调用这个
msg.recycleUnchecked();
}
}
3.使用Handler.setTarget()
或者Handler.post(...)
在本质上就是往本线程对应的Looper传入一个message,也就是进栈或进队列操作,但两种方法有一个细微区别,setTarget()
的结果是使得message.callback = null
,而post(Runnable r)
则是使得message.callback = r
。这个细微区别就导致了是该条message的处理时机。实际上参照第2点代码可以知道,方法loop()
中每次出栈或出队列都会调用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);
}
}
明显可以看到方法内会根据message.callback
是否为空选择不同的操作来执行,也就是说,如果Handler调用的不是setTarget()
,而是post()
的话,是不会执行Handler的handleMessage(msg)
的,而是直接调用post(Runnable r)
中的参数
还有相当重要的一点是,主线程会自动调用Looper.prepareMainLooper();
来完成Looper的初始化,而我们手动创建的线程是需要自己去手动调用Looper.prepare()
完成初始化才可以获得一个指向MessageQueue的Looper。
看完终于明白了Handler的运行机制的一点理解,随手写下来加强记忆,如果有错误,请指正。