View中的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
有值的情况下,一种是没有。
有值的情况下很简单,就是调用了它内部的mHandler对象,它是一个Hanlder对象,这样这个runnable会被直接执行。
@UnsupportedAppUsage
final Handler mHandler;
mAttachInfo没有值情况下
会调用getRunQueue方法,如下:
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}
它创建了一个叫做HandlerActionQueue
的对象,来看下这个类的核心实现,如下:
public class HandlerActionQueue {
private HandlerAction[] mActions;
private int mCount;
public void post(Runnable action) {
postDelayed(action, 0);
}
public void postDelayed(Runnable action, long delayMillis) {
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
synchronized (this) {
if (mActions == null) {
mActions = new HandlerAction[4];
}
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
private static class HandlerAction {
final Runnable action;
final long delay;
public HandlerAction(Runnable action, long delay) {
this.action = action;
this.delay = delay;
}
public boolean matches(Runnable otherAction) {
return otherAction == null && action == null
|| action != null && action.equals(otherAction);
}
}
}
这个类的post就是刚才getRunQueue().post(action)调用的,然后它内部是调用了自己的postDelayed方法,这个方法把传过来的Runnable又包装了一层成了HandlerAction,然后存到数组中。然后就没了。
那我的Runnable啥时候执行的?它提供了executeActions函数用于执行所有的HandlerAction,也就是封装了我们Runnable对象的对象,这个方法在View的dispatchAttachedToWindow方法中被调用,如下:
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
//... ...
// Transfer all pending runnables.
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
//... ...
}
这时mAttachInfo就有值了,然后就是调用了executeActions方法,把存下来的Runnable全部执行。dispatchAttachedToWindow之后的所有view.post都会直接通过mHandler执行,无需等待。因为mAttachInfo已经有值了。
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;
}
流程如下: