前言
在开发中,我们经常会使用到view的 post 方法或 postDelayed 方法,那么这两个方法有什么用呢?它们的使用原理是怎么样的呢?带着问题往下看:
一、post源码分析
代码如下:
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
getRunQueue().post(action);
return true;
}
从源码逻辑很清楚的看到当attachInfo 不为null时,直接调用 attachInfo.mHandler.post 执行消息,否则调用getRunQueue().post(action),最后都是交由handler去执行刷新布局。
1.mAttachInfo是什么及赋值
代码如下:
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
if (mOverlay != null) {
mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
}
// Transfer all pending runnables.
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
// 省略无关代码
}
}
从上可知,mAttachInfo 是在dispatchAttachedToWindow()中赋值的,而dispatchAttachedToWindow 是在 ViewRootImpl 类的performTraversals 调用的,而这个方法在view初始化的时候会被调用,并将 ViewRootImpl 对象的 mAttachInfo 属性传递过来,赋值给 View 对象的 mAttachInfo 属性。
2.getRunQueue()介绍
代码如下:
private HandlerActionQueue getRunQueue() {
if (mRunQueue == null) {
mRunQueue = new HandlerActionQueue();
}
return mRunQueue;
}
由上可知,getRunQueue()是返回一个HandlerActionQueue对象,并赋值给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;
}
}
\\省略相关代码
...
}
由上可知,当attachInfo 为null时,并执行getRunQueue().post(action)时,会将任务缓存在HandlerAction中,接下来在dispatchAttachedToWindow中会通过 mRunQueue 判断:View 添加到视图树之前,是否 View 添加了要处理的消息,如果是,则调用 mRunQueue 对象的 executeActions 方法,最终通过handler去执行任务。
二、postDelayed源码分析
原理与post一致
总结
1、post和postDelayed的原理和作用几乎一样,都是用来更新ui,差别的是postDelayed有延迟的功能。
2、mAttachInfo 对象是在 ViewRootImpl 对象初始化时创建的,并且在子 View 添加到视图树的时候,传递给子 View 的。
3、dispatchAttachedToWindow 执行的时候,会将 ViewRootImpl 对象的 mAttachInfo 属性,传递过来,并赋值给 View 对象的 mAttachInfo 属性。
4、当一个view调用 post/postDelayed 方法时,如果 mAttachInfo 不为空,表示该 View 已经添加到视图树了,直接调用 attachInfo.mHandler.post 执行消息,否则调用getRunQueue().post(action)缓存起来,当执行到dispatchAttachedToWindow时就直接调用handler的post执行任务。