Handler
Looper
prepare 创建线程的消息队列
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
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中的成员变量: ![image.png](https://img-blog.csdnimg.cn/img_convert/882383c49ff74d5a0f205254ba05a257.png#clientId=ucdde6d35-5eb3-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=256&id=u666c5e48&margin=[object Object]&name=image.png&originHeight=320&originWidth=1020&originalType=binary&ratio=1&rotation=0&showTitle=false&size=39108&status=done&style=none&taskId=uf0254fe4-5efb-4c32-8fa5-2008fe07916&title=&width=816) 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 (;;) {
Message msg = queue.next();
if (msg == null) {
return;
}
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
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)) {
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
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() {
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) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
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);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
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 {
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
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实现 ![image.png](https://img-blog.csdnimg.cn/img_convert/a0a265d4faecb5a32e9007f2271a3a6d.png#clientId=u9b8dbcc3-0369-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=290&id=ue8dc4b15&margin=[object Object]&name=image.png&originHeight=362&originWidth=1034&originalType=binary&ratio=1&rotation=0&showTitle=false&size=39740&status=done&style=none&taskId=u9c8754d8-c954-4079-a1b2-d610bf45da5&title=&width=827.2) 处理消息,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方法中看到最后:
if (needWake) {
nativeWake(mPtr);
}
问题2 :屏障消息工作原理梳理一下
让异步消息消息优先同步消息执行 1.设置同步屏障postSyncBarrier
private int postSyncBarrier(long when) {
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
if (prev != null) {
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
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);
}
getRunQueue().post(action);
return true;
}
这里会对mAttachInfo判空,要看下mAttachInfo的初始化时机,即dispatchAttachedToWindow方法中
void dispatchAttachedToWindow(AttachInfo info, int visibility){
mAttachInfo = info;
}
dispatchAttachedToWindow在第一次执行performTraversals()方法中调用 ![image.png](https://img-blog.csdnimg.cn/img_convert/12d0222f0777496c3c07f2d402964dc5.png#clientId=u9b8dbcc3-0369-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=301&id=u62505691&margin=[object Object]&name=image.png&originHeight=376&originWidth=982&originalType=binary&ratio=1&rotation=0&showTitle=false&size=62727&status=done&style=none&taskId=ufa2b23a5-a764-4186-b96e-53b1e28ffeb&title=&width=785.6) performTraversals这个是在哪个方法里初次调用呢?在ActivityThread.handleResumeActivity()中, ![image.png](https://img-blog.csdnimg.cn/img_convert/c04a4d30be01fe930840e739fa33adfb.png#clientId=u535965d8-657d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=446&id=u2e518072&margin=[object Object]&name=image.png&originHeight=557&originWidth=953&originalType=binary&ratio=1&rotation=0&showTitle=false&size=77372&status=done&style=none&taskId=ueedb464a-45a3-480c-b4bc-b931347b561&title=&width=762.4) 所以,在onCreate()方法中确实获取不到view的宽高;
- 如果attachInfo不为null,则执行 attachInfo.mHandler.post(action);
attachInfo中的mHandler是在ViewRootImpl中new出来的,所以这里还是通过handler去发送主线程消息执行action。 ![image.png](https://img-blog.csdnimg.cn/img_convert/5ef474e31784ab2b0f3295a3ab73a96b.png#clientId=u535965d8-657d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=72&id=u27efb092&margin=[object Object]&name=image.png&originHeight=90&originWidth=784&originalType=binary&ratio=1&rotation=0&showTitle=false&size=7969&status=done&style=none&taskId=u484a26d9-2ba7-4d2e-87fe-88652d1cf00&title=&width=627.2)
- attachInfo为null的情况,则执行 getRunQueue().post(action),这种情况只会出现在控件布局初次绘制的时候,将所有的post操作保存起来,在dispatchAttachedToWindow中执行,正常情况下直接通过1就可以发送到主线程执行了
![image.png](https://img-blog.csdnimg.cn/img_convert/11554dbc5795c75c72f5746feee44463.png#clientId=uca6bd235-960b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=114&id=ue29c47d0&margin=[object Object]&name=image.png&originHeight=114&originWidth=502&originalType=binary&ratio=1&rotation=0&showTitle=false&size=8962&status=done&style=none&taskId=u3606f66f-9a6c-49d0-a137-f474c3d7aff&title=&width=502) 这个runQueue是view持有的一个数组容器 ![image.png](https://img-blog.csdnimg.cn/img_convert/9fdae171a8beb424daaa6edd43bd8e9d.png#clientId=uca6bd235-960b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=103&id=u337af1df&margin=[object Object]&name=image.png&originHeight=103&originWidth=440&originalType=binary&ratio=1&rotation=0&showTitle=false&size=12493&status=done&style=none&taskId=u29546b9a-f81e-41e3-83e2-09e97e5ba29&title=&width=440) ![image.png](https://img-blog.csdnimg.cn/img_convert/edc336a6e18be3971850724c92e0dd38.png#clientId=uca6bd235-960b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=122&id=u6eb77c52&margin=[object Object]&name=image.png&originHeight=122&originWidth=507&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10711&status=done&style=none&taskId=u0b794246-2d16-401d-a650-a06cf536fd9&title=&width=507) dispatchAttachedToWindow中 ![image.png](https://img-blog.csdnimg.cn/img_convert/712ee3c5c62327a3fbedb6af2b714cb2.png#clientId=uca6bd235-960b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=159&id=u16c2d1c4&margin=[object Object]&name=image.png&originHeight=159&originWidth=598&originalType=binary&ratio=1&rotation=0&showTitle=false&size=14555&status=done&style=none&taskId=u82f7b02e-31b5-488f-83ce-d1fbda7d754&title=&width=598) 所以本质上说view的post方法还是通过handler去执行的,应该说没啥区别。
那为什么在onCreate中通过post执行就可以获取宽高呢? 上面已经说了初次绘制的时候executeActions是在dispatchAttachedToWindow中执行的, dispatchAttachedToWindow这个方法是执行在三大步骤之前的,那为什么能够获取宽高呢? 因为三大步骤本身所在的方法就是一次主线程的事件,executeActions是将所有的action通过msg添加到MessageQueue中而且是同步的事件,所以要等三大步骤走完去执行,这个时候自然是可以获取到宽高的。
问题4:为啥设计成单线程更新UI呢?
为啥子线程不可以更新UI?这也是个问题,其实是可以更新的,初次绘制的话在上面的handleResumeActivity执行之前就可以,这个时候viewRootImpl还没有初始化,没有做线程check。 那为啥不设计成可以在子线程更新呢?这样岂不是很多情况下效率更高。如果这么做的话就要考虑到控件的同步处理,界面的渲染、响应可能会莫名其妙的脱离用户操作的预期,保证同步性就要加大量的锁,即使粒度再细也很复杂,想一想源码控件中到处是锁的场景就头皮发麻,而且api的效率也不高。另外,像wing qt windows 这些图形界面都会采用单线程的模式相对简单成熟。
总结
MessageQueue才是hander的核心,hander支撑了主线程的执行机制,也体现了主线程的工作原理。hander在android的渲染机制中也是非常重要的。
|