一.Handler消息传递机制解决的问题
线程通信
耗时工作(从服务器拉去数据) | 更新UI |
---|---|
子线程(避免方式ANR,就是主线程卡死) | 主线程 |
要想在子线程做完耗时工作后及时更新UI,就必须使用Handler消息传递机制。
二. Handler工作流程
-
Handler.post/sendMessage 方法最终都会调用enqueueMessage将消息放入消息队列
2.在子线程中放入消息,在主线程中取出消息
三. 源码分析
enqueueMessage
将消息插入到消息队列的正确位置
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;
}
Looper
queue.next();从消息对列中取出消息,如果没有消息就阻塞(主线程进入休眠)。
msg.target就是Handler
msg.target.dispatchMessage(msg)调用Handler的dispatchMessage处理消息
Looper的参考
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;
}
try {
msg.target.dispatchMessage(msg);
}
}
}
Handler
处理消息
mCallback是Handler带参构造函数new Handler(new Handler.Callback())传入的。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}