v.post { }
Handler().post { }
View#post方法源码
- 业务场景:当我们在activity#onCreate或是在fragment#onViewCreated方法中直接获取view的宽高为0,为什么?
根据View视图的绘制流程,view的宽高只有在测量之后才能获取到,而view的测量是在activityThread的handleResumeActivity方法中,通过创建ViewRootImp,把DecoreView和ConetentView连接起来,调用perfromTravels(),进而完成view的测量布局和绘制。所以获取的值为0。
- 如何获取到宽高?
view.post { //在这个方法内部就能获取到宽高 }
跟进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;
}
我们发现当attachInfo != null时候,会通过handler把消息加入消息队列中执行,但是当这个值为null,会把这个Runnable加入到一个数组队列中。等待执行。
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++;
}
}
- 什么时候执行存储在数组中的Runnable呢?
ViewRootImp#perfromTravels(),在View测量布局绘制之后执行,所以在view#post中能获取宽高值
//开始调用handler处理view在没有mAttachInfo的情况下,view.post会存runnable任务到一个数组中,在此时通过handler去执行,加入消息队列中去
getRunQueue().executeActions(mAttachInfo.mHandler);
Handler().post
- handler#post和View#post有什么区别?
看源码实现,直接把Runnable加入到消息队列中,等待执行。和view#post相比,其实就是多了个attachInfo判断,view中如果attachInfo != null,同样是调用了handler#post方法,同样的逻辑。
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* @param r The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}