登录

去注册

登录

注册

去登录

注册

每日一问 在Activity 的 onResume 方法中 view.postRunnable 能获取到 View 宽高吗?

xiaoyang   2019-07-11   收藏

上一个问题 当成兄弟问题咯。


如果可以,为什么?

8

刚睡醒,看到标题我还想着:咦,怎么两个一样的问题?难道是机器发贴的?哈哈哈哈哈哈哈,点进来之后才发现不是。


在onResume方法中,调用View的post方法,里面的Runnable是可以获取到View的宽高的。

为什么?

看下代码:

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不为空的时候,会调用mAttachInfo里面的Handler的post方法,但如果为空呢,就会调用getRunQueue()方法返回的对象的post方法。
点开getRunQueue()方法会看到返回的是mRunQueue,这个mRunQueue上面有注释写着:

Queue of pending runnables. Used to postpone calls to post() until this view is attached and has a handler.

就是说,view在attach之前(dispatchAttachedToWindow被调用之前),添加到mRunQueue的Runnable都会被挂起,直到这个view attach之后,才会执行。

那什么时候attach呢?

在ViewRootImpl的performTraversals方法第一次被调用的时候。

这时候有同学就会问:我也看了源码,知道了RootView的layout方法是在ViewRootImpl的performLayout方法里面调用的,但是我明明看到,dispatchAttachedToWindow方法是在performLayout方法之前调用的!!!那不就是说,dispatchAttachedToWindow回调的时候,View还没layout嘛?那怎么能获取到的?

是啊,dispatchAttachedToWindow回调的时候,View确实还没被layout,

但是不要忘了!刚刚调用View的post方法传进去的Runnable,最终也是会作为Handler的postDelay方法的参数的,

也就是说,这个Runnable并没有立即执行,只是放到MessageQueue里面排队而已,

最重要的一个就是:本次执行performTraversals方法的task,它也是从MessageQueue取出来的!那就代表这必须要等这个task执行完毕(performLayout方法也就执行完毕了)之后,才会轮到下一个。


回复
陈小缘 : @xujf1128 

哈哈哈,不是的,我昨晚刚好有点累,就想着躺一下,结果不小心睡着了,哈哈哈哈哈

2019-07-10 回复
xujf1128 : @陈小缘 

大佬的作息,惊了

2019-07-10 回复
0

开森,又 get 到知识。

是可以的。

答:activity onResume 回调执行在 DecorView 的测量之前,然后才是 ViewRootImp 发送同步消息障碍并并发送一条异步消息,在执行回调中执行 DecorView 的测量、布局、绘制的流程,在执行测量之前会调用 View dispatchAttachedToWindow 方法,而在该方法中会将在 onResume view.post() 需要执行的任务添加到主线程的 Handler 消息执行队列中,最后待 ViewRootImp view 的测量、布局、绘制等流程执行完毕之后就会执行 view.post() 设定的任务了,这样就能获取到 view 的宽高了。


回复
0

今天有意的去看了下 post的源码。楼上的已经说了具体的流程就不赘述了。

直接说结论。

1.可以获取到View的宽高。View内部还是使用Handler,在View.#dispatchAttachWindow 和 ViewRootImp#performTraversals 都分别调用了 getRunQueue().executeActions(mAttachInfo.mHandler);至于先后顺序楼上也已经解答了。

2.顺便说一下。昨天还是前天工作中我使用 View.post(() -> {startAnimation()....});,leader review 代码的时候告诉我说尽量不要用这个方法,说是在低版本的时候不执行。于是我看了下网上的文章加上看了一下源码发现是这样。于是怎么解决的呢?对View.addOnGlobalLayoutListener();这个方法是最靠谱的。具体的细节在这里 https://blog.csdn.net/longlong2015/article/details/88826269


回复
0

没明白

回复
0

本周2/3

回复

删除留言

确认删除留言,会导致相关评论丢失?

取消 确定