更多问答 >>
-
2019-07-14 21:09
-
每日一问 如果项目要开始做编译速度优化,你会考虑从哪些地方入手?
2019-07-16 23:50 -
每日一问 哪些 Context调用 startActivity 需要设置NEW_TASK,为什么?
2019-07-18 23:24 -
每日一问 Android 常见的制作圆角方案,有哪几种常见方式? 在Android P上什么兼容性问题
2019-07-21 16:48 -
每日问答 Handler应该是大家再熟悉不过的类了,那么其中有个同步屏障机制,你了解多少呢?
2019-07-23 17:29 -
每日一问 在Activity 的 onResume 方法中 handler.postRunnable 能获取到 View 宽高吗?
2019-07-09 21:03 -
每日一问 对于代码中有大量的 if/else 你有什么优化思路?
2019-07-07 23:00 -
每日一问 | getWidth, getMeasuredWidth 有什么区别?
2019-07-05 00:48 -
每日一问 对于SharedPreferences你觉得有什么优缺点?
2019-07-02 23:35 -
每日一问 ANR的产生的原理是什么,AMS中涉及ANR的代码有哪些?
2019-06-30 22:33
刚睡醒,看到标题我还想着:咦,怎么两个一样的问题?难道是机器发贴的?哈哈哈哈哈哈哈,点进来之后才发现不是。
在onResume方法中,调用View的post方法,里面的Runnable是可以获取到View的宽高的。
为什么?
看下代码:
可以看到当mAttachInfo不为空的时候,会调用mAttachInfo里面的Handler的post方法,但如果为空呢,就会调用getRunQueue()方法返回的对象的post方法。
点开getRunQueue()方法会看到返回的是mRunQueue,这个mRunQueue上面有注释写着:就是说,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方法也就执行完毕了)之后,才会轮到下一个。
大佬的作息,惊了
哈哈哈,不是的,我昨晚刚好有点累,就想着躺一下,结果不小心睡着了,哈哈哈哈哈
今天有意的去看了下 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
背景:Android发送消息默认都是同步消息,view绘制的时候会发送异步消息来绘制view,并且会开启同步障碍(发送异步消息需要开启同步障碍才会生效:优先执行异步消息。 否则异步消息跟同步消息没有区别)。
知道了这个背景之后,就很好解释了。
hander.postRunnable在view绘制(开启同步障碍)之前,所以还是先执行handler.post出去的那个同步消息,于是就获取不到宽高;view.post在view绘制(开启同步障碍)之后,就先执行绘制的系统消息,执行绘制,再执行view.post发出去的消息,这也解释了一个可以获取view的宽高,一个不可以。仅个人理解,希望大佬们指正。
开森,又 get 到知识。
是可以的。
答:activity 的 onResume 回调执行在 DecorView 的测量之前,然后才是 ViewRootImp 发送同步消息障碍并并发送一条异步消息,在执行回调中执行 DecorView 的测量、布局、绘制的流程,在执行测量之前会调用 View 的 dispatchAttachedToWindow 方法,而在该方法中会将在 onResume 中 view.post() 需要执行的任务添加到主线程的 Handler 消息执行队列中,最后待 ViewRootImp 对 view 的测量、布局、绘制等流程执行完毕之后就会执行 view.post() 设定的任务了,这样就能获取到 view 的宽高了。
生命周期如下
handleResumeActivity -> onResume ->Activity.makeVisible() -> getViewRootImpl.scheduleTraversals -> performTraversals -> DecorView.dispatchAttachedToWindow(attachInfo) -> getRunQueue().executeActions(mAttachInfo.mHandler) -> layout ->MessageQueue取出HandlerAction数组信息进行执行重点post只是缓存HandlerAction数组,layout之后才会从缓存actions中post主线程进行执行能,因为view都attach完了。
没明白
本周2/3