跟Handler有关系的,包括Thread,Looper,Handler,MessageQueue
Looper:
由于Looper是android包加入的类,而Thread是java包的类,所以,想要为Thread创建一个Looper,需要在线程内部调用Looper.prepare
Looper内部会存储一个ThreadLocal,因此每个线程都会有自己的一个Looper。
Looper内部有自己存储了一个MessageQueue,以及主线程的MainLooper。
调用Looper一般会有两个方法:Looper.prepare以及Looper.loop方法
Looper.prepare
prepare会新创建一个Looper,塞进ThreadLocal,因此prepare必须在线程内部调用,才能将线程本身作为key。
同时,会创建MessageQueue,以及存储当前线程。
顺便看下两个比较常用的方法:
myLooper是从ThreadLocal中获取的当前线程所属的Looper。
myQueue对应的是当前线程的Looper中存储的MessageQueue。
Looper.loop
从Looper.loop方法,可以看出几个细节:
- 通过调用MessageQueue.next获取下一个要处理的Message
- 通过Message.target.dispatchMessage,将Message提交给Message中存储的Handler去处理,Handler调用dispatchMessage
- 可以创建一个进程唯一的Observer去监听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.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
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;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", 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();
}
}
Message
从Looper.loop方法可以看出,会对Looper的MessageQueue遍历,不断取出Message,然后调用Message.target.dispatchMessage方法。
从Message的变量可以看出,target实际是Message所属的Handler。
同时Message存储了一个next,说明MessageQueue是一个链式结构。
MessageQueue
https://www.cnblogs.com/jiy-for-you/p/11707356.html
从MessageQueue.next可以获取几个有效信息:
- nativePollOnce:MessageQueue中没有Message的时候会卡在这个方法,类似于object.wait,当有人调用MessageQueue.enqueueMessage方法的时候,会将线程唤醒。
- msg.target == null,代表该msg是一个同步屏障(即阻拦同步消息的执行)。遇到同步屏障时,会往后遍历,优先执行异步消息(触发view的绘制的那个消息就是异步消息)。
- 如果获取到一个msg,msg.when代表的执行时间还没到,会先去执行IdleHandler里面的消息(或MessageQueue队列为空)。
// MessageQueue.next
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();
}
// 如果没有消息,会卡在这个方法
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) {// 同步屏障,当遇到同步屏障,会往后寻找异步消息(isAsynchronous)执行
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {// 遍历,直到找到一个异步的msg
prevMsg = msg;// 这一步,prevMsg!=null,这会导致
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {// msg.when是这个message的执行时间,如果message的执行时间在now之后
// 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;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
// 走到这,说明消息队列是空的,或队首是一个延迟执行的Message
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
Handler的总结:
- Handler内部一定会有一个Looper。Looper跟线程一一绑定。绑定的关系存在Looper的sThreadLocal中。所以如果Handler想要监听哪个线程上的消息,可以直接给Handler传那个线程的Looper即可。
- Looper实际上是一个轮询消息的机制,所以内部一定会存在一个MessageQueue。当Looper开始轮询的时候(调用Looper.loop),会每次调用MessageQueue.next取一个Message出来执行。
- Looper获取到Message之后,会调用Message.target.dispatchMessage方法。即实际调用的是Handler.dispatchMessage的方法。
- Message中有几个比较重要的参数:
- target:这个Message从属于哪个handler(从哪个handler post过去的)。
- callback:当调用handler.postRunnable,即创建了一个Message,msg.callBack = runnable。
- what:这个Message的唯一标识id。当Handler.handleMessage方法中,会接收多个message,通过what区分这个Message的类别。
- when:通过handler.postDelayed,设置这个Message实际应该执行的时间:curTime+delay。MessageQueue的入队实际是通过when去进行Message的排序的。
- handler.dispatchMessage方法,
- 如果Message.callback != null,直接执行Message.callback.run(即post(Runnable))中Runnable的执行。
- 否则如果给handler设置了Callback,就调用Callback.handleMessage
- 否则,调用Handler本身的handleMessage方法(空实现),需要重写。
关于barrier
// MessageQueue
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;// 代表Message的barrier,特征是target == null
Message prev = null;
Message p = mMessages;
if (when != 0) {// 根据when,将代表barrier的msg插入MessageQueue
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
postSyncBarrier,生成一个target == null的Message,根据when,插入MessageQueue中。返回的token是barrier的唯一标识。只要postSyncBarrier,就要根据这个token,后面移除barrier。否则会导致同步消息一直无法执行。
看下有了barrier的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();
}
nativePollOnce(ptr, nextPollTimeoutMillis);// 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) {// 如果取msg的时候,队首的Msg是Barrier
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
// 就一直往后遍历,寻找一个异步的msg
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {// 如果还没到msg的执行时间,就设置nextPollTimeoutMillis
// 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 {// 如果mMessages队列为空,或有Barrier的时候,异步msg为空,就设置等待时间为-1
// 为-1代表等待被唤醒
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}// 如果队列为空,或者还没到message的执行时间,开始执行IdleHandler
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
// 防止下次再走一遍IdleHandler
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
// 经过IdleHandler之后,可能已经有Message入队了,再遍历一遍,第二次就直接等待了。
nextPollTimeoutMillis = 0;
}
}
总结下next的逻辑:
- 如果mMessages的队首是barrier(msg.target == null),就遍历messages,优先执行异步消息(异步消息一般是优先级最高的信息:比如响应input事件或是view刷新。)。
- 如果不是barrier,就直接取队首的message执行。
- 如果1,2步骤取到的message != null,先看message的when < now,大于则直接返回message给Looper.loop方法。小于,则设置nextPollTimeoutMillis,用来设置线程的等待时间:nativePollOnce。
- 如果messageQueue为空,或message.when > now(即要等待),那么这个时候,就去执行IdleHandler。
总结下上面,nativePollOnce其实代表,线程在等待下一个消息的执行,或者messages队列为空。或者是设置了barrier情况下,没有异步消息的时候。
下一步,看下MessageQueue的具体打出日志代表什么。