Android layout measuring time doubles with each step up the hierarchy

早过忘川 提交于 2019-12-07 20:33:29

Previous answer from Simon isn't quite right. True there's a measure pass and and a layout pass, but that fact alone doesn't cause exponential blowup.

If you put traces inside onMeasure() and onLayout() on the various Views in the hierarchy, you'll find that the layout pass is not a problem: onLayout() only gets called once on each View, making it a linear-time traversal. The measure pass is the problem-- for some subclasses of ViewGroup, with some parameters, onMeasure() ends up calling each child's onMeasure() twice, which of course leads to exactly the behavior you're seeing.

RelativeLayout is one of these "bad citizens" that measures each child twice, agreeing with your observation.

Another bad citizen (as you know) is LinearLayout when children have MATCH_PARENT and nonzero weights. I've looked at the implementation and I roughly follow what it's doing-- first it recursively measures the children once to see how big they'd like to be, then, if there is any slack (or shrinkage), it measures the children with nonzero weights again in order to distribute the slack.

Note that RelativeLayout is often cited as a solution to the exponential blowup, even though it is one of the bad citizens causing it. I believe the reasoning is that RelativeLayout is expressive enough that deep hierarchies of LinearLayouts can be re-expressed as a single RelativeLayout. This is a very important point-- if you simply replace LinearLayouts with RelativeLayouts without flattening the hierarchy, you'll still have exponential measure times.

It's unclear to me whether the exponential blowup is something that can be eventually be simply optimized away in the core libraries (perhaps by separating the existing measure pass into a gather-preferred-sizes pass and a distribute-slack pass, each of which can be done in linear time and which don't need to call each other) or whether there is something in LinearLayout's and RelativeLayout's contracts that make the recursive double-measuring-of-children inherently necessary.

Android builds layout in 2 passes.

The first is the measure pass, when all children are asked how large they want to be. Then a layout pass, when the parent tells the children how big they are and requests them to draw.

Therefore, adding an extra ViewGroup level roughly doubles the time. This is consistent with the examples you've given.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!