在开发过程中非主线程更新UI,第一个想到的就是通过Handler来刷新UI,那Handler是如何工作的呢?
Handler
Handler
是消息处理器,负责Message
消息的发送和处理。
mHandler.sendMessage(msg)
非常熟悉的方法,跟踪这个方法,可以发现Handler
通过enqueueMessage()
的方法将Message
消息对象放入MessageQueue
消息队列中
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
通过dispatchMessage()
来调用具体的处理,由Looper.loop()
调用,具体如何调用后面给出
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 看到这里是不是就很熟悉,这里就是我们经常复写来处理具体消息的方法
handleMessage(msg);
}
}
Message
Message
是消息的model类,负责数据的传递。非主线程刷新UI时,就需要一个创建一个Message
对象。
创建Message
的常用方式有两种new Message()
,Message.obtain()
,推荐使用Message.obtain()
可以减少Message
对象的创建
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
// 先判断对象池中是否有可以利用的Message对象
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
// 对象池中是没有Message对象,那么会new 一个新的对象
return new Message();
}
MessageQueue
MessageQueue
是消息队列,Handler
对象通过内部方法queue.enqueueMessage
将Message
消息发送到MessageQueue
中
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
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;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
之后Looper
循环处理器通过queue.next()
方法从MessageQueue
中获取需要处理的Message
消息
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// nextPollTimeoutMillis= -1时候,这里会阻塞线程,在native层使用了epoll机制来等待消息
nativePollOnce(ptr, 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 (DEBUG) Log.v(TAG, "Returning message: " msg);
msg.markInUse();
return msg;
}
} else {
// No more messages. 没有消息时将nextPollTimeoutMillis设置为-1
nextPollTimeoutMillis = -1;
}
/*
* 删除了一些无关代码
*/
}
}
Looper
最后再来说下Looper
,Looper
是一个循环处理器,负责消息的分发处理。通过Looper.loop()
不停的处理MessageQueue
中的消息,直到消息队列为空,之前已经提到Loop
通过queue.next()
方法从MessageQueue
中获取等待处理的消息
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
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 (;;) {
// 这里循环从queue中获取Message消息,如果没有消息的话这里会阻塞
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
try {
//msg.target 对象是发送Message消息的Handler对象,通过Handler的dispatchMessage进行消息处理
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
/*
* 删除了一些无关代码
*/
// 消息处理完后,将Message放入对象池中,这样Message.obtain()获取Message时候可以减少对象的创建
msg.recycleUnchecked();
}
}