综上,view.post(runnable)都是通过attachInfo.handler发送消息,由handler分发处理。
attachInfo是在dispatchAttachedToWindow中赋值,在dispatchDetachedFromWindow中移除的。
//View.java
//投递消息
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) { //attachInfo已经赋值,则直接通过attachInfo.handler执行
return attachInfo.mHandler.post(action);
}
getRunQueue().post(action); //否则放入HandlerActionQueue中,等待时机处理
return true;
}
//取消执行runnable对象,和post对应
public boolean removeCallbacks(Runnable action) {
if (action != null) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mHandler.removeCallbacks(action);
attachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
Choreographer.CALLBACK_ANIMATION, action, null);
}
getRunQueue().removeCallbacks(action);
}
return true;
}
AttachInfo mAttachInfo;
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
// Transfer all pending runnables.
if (mRunQueue != null) { //attachInfo.handler执行之前存储的runnable信息
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
}
void dispatchDetachedFromWindow() {
mAttachInfo = null;
}
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}
public class HandlerActionQueue {
private HandlerAction[] mActions;
private int mCount; //集合容量
public void post(Runnable action) {
postDelayed(action, 0);
}
public void postDelayed(Runnable action, long delayMillis) {
//将runnable 和 delayTime 包装成一个HandlerAction对象
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
synchronized (this) {
if (mActions == null) { //默认初始化数组对象容量为4,
mActions = new HandlerAction[4];
}
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}
//更新集合数据mActions
public void removeCallbacks(Runnable action) {
synchronized (this) {
final int count = mCount;
int j = 0; //j是新的,处理过的的Hnadler集合索引
final HandlerAction[] actions = mActions;
for (int i = 0; i < count; i++) { //i是实际的Hnadler集合索引
if (actions[i].matches(action)) {
continue;
}
if (j != i) { //不匹配,用后面的覆盖前面的(j肯定小于等于i)
actions[j] = actions[i];
}
j++;
}
mCount = j; //集合的容量更新
for (; j < count; j++) { //集合被清除的数据赋为null
actions[j] = null;
}
}
}
//通过handler发送message的形式,在handler所在的线程执行所有action
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);
}
}
}
attachInfo是在ViewRootImpl的构造函数中实例化的,mHandler的looper是当前线程(主线程)的looper对象,handler也是在主线程中处理消息的
ViewRootImple是在onResume之后,在WindowManagerGlobal中实例化的,并通过setView(view, display)绑定了decorView,viewRootImpl是decorView的parentView
setView中通过requestLayout发起布局绘制请求,在下一个16.66ms到来时,执行performTraversals()。
在performMeasure之前,通过host.dispatchAttachedToWindow(attachInfo),遍历decorView,将attachInfo绑定到每一个View/ViewGroup身上,才能通过attachInfo.handler发消息执行所有runnable对象
runnable对象是在performTraversals()执行完毕后,handler才会继续从messageQueue中取message,在主线程中执行,所以view.post(runnable)能拿到View的宽高等测量绘制信息。
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
final View.AttachInfo mAttachInfo;
final ViewRootHandler mHandler = new ViewRootHandler();
//ViewRootImpl实例化时,attachInfo也实例化
public ViewRootImpl(Context context, Display display) {
mFirst = true; // true for the first time the view is added
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this, context);
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout(); //发起布局绘制请求
view.assignParent(this);
}
}
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
if (host == null || !mAdded)
return;
if (mFirst) {
host.dispatchAttachedToWindow(mAttachInfo, 0); //分发attachInfo给每一个view、ViewGroup
}
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, mWidth, mHeight);
performDraw();
}
}
decorView分发attachInfo给每一个View/ViewGroup
//ViewGroup.java
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
super.dispatchAttachedToWindow(info, visibility);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
final View child = children[i];
child.dispatchAttachedToWindow(info,
combineVisibility(visibility, child.getVisibility()));
}
}
参考:
【Android源码解析】View.post()到底干了啥