这个问题很明确了,想必大家都能了解,我们经常在自定义 View 的时候,会发现 onMeasure 执行了多次?
那么问题来了:
onMeasure 执行多次的原因有哪些呢?
更多问答 >>
-
每日一问 | view.requestLayout如果在灭屏或者切home之后调用会怎么样?
2021-05-06 00:16 -
每日一问 | 已经有了 Intent,那为啥还要 PendingIntent?
2021-05-28 00:29 -
2021-05-28 00:29
-
每日一问 | Dialog 的构造方法的 context 必须传入 Activity吗?
2021-07-11 22:06 -
2021-07-11 22:06
-
每日一问 | 听说你做过内存优化 之 Bitmap内存占用到底在哪?
2021-04-19 23:40 -
2021-04-08 00:25
-
每日一问 | mipmap vs drawable,傻傻分不清楚?
2021-03-30 21:14 -
每日一问 | onDraw 里面调用 invalidate 做动画,有什么问题?
2021-04-13 00:31 -
每日一问 | 在做性能优化的时候,常常看到 Thread(Cpu) Time,Wall clock Time?
2021-03-15 00:43
补充:
除了源头ViewRootImpl发起的Measure,还应该考虑各个ViewGroup自身的Measure逻辑,因为ViewRootImpl只有首次Traversals、屏幕旋转、DecorView宽度为WRAP_CONTENT等特殊情况下才会有超过1次的Measure。按照正常流程,View.onMeasure
的执行完全是看它父容器何时调用它的measure
方法,如果在ViewGroup.onMeasure
中多次调用子View的measure
方法,那子View.onMeasure
自然也就回调多次了。不过,由于每个ViewGroup它的onMeasure
都可能有自己的实现,这样就很难把所有情况都一一列举出来。就拿最常用的LinearLayout来看:它是根据排列方向来选择不同的测量方案,先看垂直方向的:
(注意:targetSdkVersion > 28那里,应该是27,图片昨晚弄的,现在改不了了)根据上图的测量逻辑,我们很容易写出一个让子View回调3次onMeasure
的xml:弄一个View重写
onMeasure
来监听回调:运行看一下:
哈哈,看到了吧,first traversals之后,每次
LinearLayout测量水平方向的逻辑也差不多:(注意:targetSdkVersion > 28那里,应该是27,图片昨晚弄的,现在改不了了)只是在第一个for里面增加了一对if else而已。有没有发现,LinearLayout回调多次的主要原因,就是子View中有设置requestLayout
都会回调三次onMeasure
方法。weight
? 如果子View没有设置weight
的话,那么在同一个Measure流程内,最多只会回调2次onMeasure
方法。再来看一个FrameLayout的测量逻辑:
我们同样可以写出以下xml代码让FrameLayout的子View分别回调2次onMeasure
:总结:
View.onMeasure
方法的回调次数,主要取决于它所在的容器的onMeasure
逻辑,搭配不同ViewGroup和设置不同属性都会有影响,所以很难有一个标准、统一的答案。当我们使用LinearLayout时,应尽量避免使用weight
属性(说是这么说,但其实多测量几次也不会花太多时间,我们根本感觉不出来,除非你的自定义View的测量逻辑真的很复杂,很耗时。不过,要是你的View的测量很耗时的话,应该优化的是这个View本身,而不是从别的地方下手。。。)(想看更详细的ViewRootImpl测量逻辑的同学可以留言,我这周内更新)求小缘加更
缘神,线性布局那里,api29 requestLayout onMeasure 了一次。
我们知道,页面的根布局为
当我们使用DecorView
,附着在PhoneWindow
上setContentView
设置布局时,就是使用ViewRootImpl
将我们的布局添加到根布局上当ViewRootImpl
添加View
时,就会测量多次第一次是:measureHierarchy
第二次是:performMeasure两次调用函数栈如图所示:原因有两个: