1

I'm analyzing a tablet UI in hierarchyviewer and I noticed the following pattern in measure times (starting from the base of the tree and moving up):

... ~40 ms ... ~80 ms ... ~160 ms ... ~320 ms ... ~640 ms ... ~1280 ms ...

I assumed the problem was LinearLayouts with nested weights, so I removed ALL LinearLayouts and weights in the whole hierarchy. Now I have this:

... ~40 ms ... ~80 ms ... ~160 ms ... ~160 ms ... ~160 ms ... ~310 ms ...

Better, but it still doubles every few levels. What could be causing this?

Here is the full hierarchy for this path (pardon the length... feel free to throw your best optimization tips at me):

[generated layouts]
 *RelativeLayout [309 ms]
   FrameLayout [164 ms]
    NoSaveStateFrameLayout [160 ms]
    *RelativeLayout [151 ms]
     *RelativeLayout [77 ms]
       ListView [45 ms]
        GridLayout [46 ms]
         Spinner [4.4 ms]
          TextView [0.1 ms]

*view time doubles

Any advice will be greatly appreciated! Thanks in advance.

TL;DR

Other than nested weights, what causes exponential increase in measure times?

4

2 回答 2

4

西蒙以前的回答不太正确。确实有一个测量通道和一个布局通道,但仅凭这一事实并不会导致指数级爆炸。

如果您在层次结构中的各个 View 上的 onMeasure() 和 onLayout() 中放置跟踪,您会发现布局传递不是问题:onLayout() 仅在每个 View 上调用一次,使其成为线性时间遍历。测量传递是问题 - 对于ViewGroup的某些子类,带有一些参数, onMeasure() 最终会调用每个孩子的 onMeasure() 两次,这当然会导致您所看到的行为。

RelativeLayout 是这些“坏公民”之一,它会测量每个孩子两次,这与您的观察结果一致。

当孩子拥有 MATCH_PARENT 和非零权重时,另一个坏公民(如您所知)是 LinearLayout。我已经查看了实现,我大致遵循它在做什么——首先它递归地测量孩子一次,看看他们想要多大,然后,如果有任何松弛(或收缩),它测量孩子再次使用非零权重以分配松弛。

请注意,RelativeLayout 经常被引用为指数爆炸的解决方案,即使它是导致它的坏公民之一。我相信原因是RelativeLayout 具有足够的表现力,可以将LinearLayouts 的深层层次结构重新表示为单个RelativeLayout。这是非常重要的一点——如果你只是用相对布局替换线性布局而不扁平化层次结构,你仍然会有指数测量时间。

我不清楚指数爆炸是否最终可以在核心库中简单地优化掉(也许通过将现有的度量传递分为聚集首选大小传递和分布松弛传递,每个都可以是在线性时间内完成并且不需要相互调用)或者LinearLayout和RelativeLayout的合同中是否有某些东西使得递归双重测量孩子本质上是必要的。

于 2013-07-05T14:45:29.533 回答
0

Android 在 2 遍中构建布局。

第一个是测量通过,当所有孩子都被问到他们想要多大时。然后是布局传递,当父母告诉孩子他们有多大并要求他们画画时。

因此,添加一个额外的 ViewGroup 级别大约会使时间翻倍。这与您给出的示例一致。

于 2012-12-12T23:49:32.160 回答