prepare 创建线程的消息队列
//保证每个线程只持有唯一looper对象 static final ThreadLocalsThreadLocal = new ThreadLocal (); 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)); } /... private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
关于ThreadLocal:
ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
map是Thread中的成员变量:

ThreadLocalMap的构造方法:
ThreadLocalMap(ThreadLocal> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
loop()开启消息循环:
for (;;) {
//next方法很关键
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、MessageQueue
消息的实体类,
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
target是一个Handler类型的变量,这也保证了一个Looper可以关联多个Handler。
when是long类型的时间戳,代表此条消息的执行时间点。
postDelayed->sendMessageDelayed->enqueueMessage
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
enqueueMessage
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; // 符合条件插入
prev.next = msg;
}
/.....
}
将when的时间戳赋值给msg,再按时间从小到大的顺序在链表中插入这条消息,循环遍历,如果when不是0的话就寻找一条大于when的msg,插入到这条msg的前面。
next():
Message next() {
/...
for (;;) {
nativePollOnce(ptr, nextPollTimeoutMillis);//阻塞操作 如果为-1,则表示无限等待,直到有事件发生为止。如果值为0,则无需等待立即返回
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;//mMessages指的是链表中存在的首个消息,会在下面赋值
//判断是否是屏障消息,屏障消息的target是为null的
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;//标记非阻塞状态,立即返回msg
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;//mMessages重新标记为头部消息
}
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.
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);
}
}
}
Handler
handler的主要作用是发送和处理消息,方法体现在
post(@NonNull Runnable r);
postAtTime(@NonNull Runnable r, long uptimeMillis)
postDelayed(@NonNull Runnable r, long delayMillis)
sendMessage(@NonNull Message msg)
sendMessageDelayed(@NonNull Message msg, long delayMillis)…
和Message的关联通过target实现

处理消息,dispatchMessage,在Looper的loop()循环中会调用到
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
产生的问题和思考:
问题 1:阻塞中的话后续无延迟消息如何保证立即执行?
_回到_enqueueMessage方法中看到最后:
//...根据mBlocked标记的阻塞状态唤醒线程
if (needWake) {
nativeWake(mPtr);
}
问题2 :屏障消息工作原理梳理一下
让异步消息消息优先同步消息执行
1.设置同步屏障postSyncBarrier
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();
//1、屏障消息和普通消息的区别是屏障消息没有tartget。
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
//2、根据时间顺序将屏障插入到消息链表中适当的位置
if (when != 0) {
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;
}
//3、返回一个序号,通过这个序号可以撤销屏障
return token;
}
}
_2._在上述的next()方法中处理异步消息。
问题 3:View的post方法和handler的post一样吗?为什么说在Activity中的onCreate中通过post就能获取宽高值?public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
这里会对mAttachInfo判空,要看下mAttachInfo的初始化时机,即dispatchAttachedToWindow方法中
void dispatchAttachedToWindow(AttachInfo info, int visibility){
mAttachInfo = info;
}
dispatchAttachedToWindow在第一次执行performTraversals()方法中调用

performTraversals这个是在哪个方法里初次调用呢?在ActivityThread.handleResumeActivity()中,

所以,在onCreate()方法中确实获取不到view的宽高;
- 如果attachInfo不为null,则执行 attachInfo.mHandler.post(action);
attachInfo中的mHandler是在ViewRootImpl中new出来的,所以这里还是通过handler去发送主线程消息执行action。

- attachInfo为null的情况,则执行 getRunQueue().post(action),这种情况只会出现在控件布局初次绘制的时候,将所有的post操作保存起来,在dispatchAttachedToWindow中执行,正常情况下直接通过1就可以发送到主线程执行了

这个runQueue是view持有的一个数组容器


dispatchAttachedToWindow中

所以本质上说view的post方法还是通过handler去执行的,应该说没啥区别。
那为什么在onCreate中通过post执行就可以获取宽高呢?
上面已经说了初次绘制的时候executeActions是在dispatchAttachedToWindow中执行的,
dispatchAttachedToWindow这个方法是执行在三大步骤之前的,那为什么能够获取宽高呢?
因为三大步骤本身所在的方法就是一次主线程的事件,executeActions是将所有的action通过msg添加到MessageQueue中而且是同步的事件,所以要等三大步骤走完去执行,这个时候自然是可以获取到宽高的。
为啥子线程不可以更新UI?这也是个问题,其实是可以更新的,初次绘制的话在上面的handleResumeActivity执行之前就可以,这个时候viewRootImpl还没有初始化,没有做线程check。
那为啥不设计成可以在子线程更新呢?这样岂不是很多情况下效率更高。如果这么做的话就要考虑到控件的同步处理,界面的渲染、响应可能会莫名其妙的脱离用户操作的预期,保证同步性就要加大量的锁,即使粒度再细也很复杂,想一想源码控件中到处是锁的场景就头皮发麻,而且api的效率也不高。另外,像wing qt windows 这些图形界面都会采用单线程的模式相对简单成熟。
MessageQueue才是hander的核心,hander支撑了主线程的执行机制,也体现了主线程的工作原理。hander在android的渲染机制中也是非常重要的。



