为什么嵌套权重对性能有害?替代方案是什么?

173

我已经编写了几个布局文件,其中使用了 layout_weight 属性来创建不同视图之间的比例。

但是,在某些时候,我开始收到有关嵌套权重的警告。

因此,我想知道为什么嵌套权重对性能不利,是否有更有效的方法可以创建视图维度之间的恒定比率,该比率可用于不同屏幕尺寸,并且不需要在多个布局文件中指定许多尺寸dpi值(我指的是针对不同屏幕尺寸)。

谢谢!


2
一个优秀的文章,关于布局优化。http://developer.android.com/training/improving-layouts/optimizing-layout.html - Muhammad Babar
6个回答

149

嵌套权重会影响性能,因为:

布局权重要求组件测量两次。当一个具有非零权重的LinearLayout嵌套在另一个具有非零权重的LinearLayout中时,测量次数指数级增加。

最好使用RelativeLayout,根据其他视图的位置调整您的视图而不使用特定的dpi值。


92
需要注意的好事,我想这就是信息的目的。但我要指出,如果涉及的指数很小,指数影响仍然微不足道。对于嵌套深度较浅的情况,不使用所需的CPU就像拥有一匹劳动马,你整个星期都在宠爱它,只在周日带它出去散步。但对于嵌套深度较大的情况,这是一个很好的观点。 - Carl
15
RelativeLayout 也需要测量两次以确保其所有子项正确布局,因此将具有布局权重的 LinearLayout 更改为 RelativeLayout 可能不会提高性能。 - Piasy
2
相对布局并不总是有效。在需要构建比例小部件的情况下, - Abdurakhmon

69

更新:我们知道从API级别26开始,百分比支持库已被弃用。ConstraintLayout是实现相同扁平化xml结构的新方法。

更新的Github项目

更新的示例:

<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/fifty_thirty"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ffff8800"
        android:gravity="center"
        android:text="@string/fifty_fifty_text"
        android:textColor="@android:color/white"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.5"
        android:textSize="25sp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="0.5" />

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ffff5566"
        android:gravity="center"
        android:text="@string/fifty_fifty_text"
        android:textColor="@android:color/white"
        android:textSize="25sp"
        app:layout_constraintHeight_default="percent"
        app:layout_constraintHeight_percent="0.5"
        app:layout_constraintLeft_toRightOf="@id/fifty_thirty"
        app:layout_constraintTop_toBottomOf="@id/fifty_thirty"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="0.5" />

</android.support.constraint.ConstraintLayout>

更新: 很好的消息,Android百分比支持库解决了我们在性能和嵌套混乱的加权 LinearLayout方面的问题。

compile 'com.android.support:percent:23.0.0'

这里有演示程序

考虑以下简单的布局以进行演示。

百分比支持库演示

<android.support.percent.PercentRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/fifty_huntv"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff7acfff"
        android:text="20% - 50%"
        android:textColor="@android:color/white"
        app:layout_heightPercent="20%"
        app:layout_widthPercent="50%" />
    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_toRightOf="@id/fifty_huntv"
        android:background="#ffff5566"
        android:text="80%-50%"
        app:layout_heightPercent="80%"
        app:layout_widthPercent="50%"
        />

</android.support.percent.PercentRelativeLayout>

避免在具有权重的嵌套LinearLayout中降低性能。真是太棒了!!!。


@dan 是的,考虑到我们有嵌套的线性布局和权重。 - Nitesh Tiwari
3
这个类在API 26.0.0-beta1中被弃用。 考虑使用ConstraintLayout及其相关布局来替代。 - saiyancoder
9
我不喜欢 ConstraintLayout。对我来说它的行为不够直观。 - Carson Holzheimer
9
ConstraintLayout 对我来说很难。 - BertKing
1
也许苹果在自动布局约束方面的解释更清晰,由于逻辑相同,这可能会有所帮助。不幸的是,我发现安卓的ConstraintLayout比iOS的AutoLayout更加繁琐。 - AdricoM
似乎app:layout_constraintVertical_weight="1"app:layout_constraintHorizontal_weight="1"的性能比使用app:layout_constraintHeight_percentapp:layout_constraintWidth_percent要好得多。 - CrandellWS

49

我认为(我可能会因此而受到批评),但是我认为我的手机拥有一个四核处理器,可以与(如果不是完全摧毁)大多数人的家用电脑相媲美。

我还认为,这种硬件能力是手机的未来。

所以我得出结论,只要您没有陷入过度嵌套的困境(在我看来,布局永远不应该超过4个级别,如果超过了,那么您可能做错了),您的手机对于有没有权重完全不在意。

有很多事情可以做,对性能产生更广泛的影响,比担心处理器做一些额外的数学更重要。

(请注意,我有点幽默,所以不要从这篇文章中太严肃地看待任何事情,除了想法之外,还有其他你应该优化的东西,并且担心2-3级别的权重并不能帮助您的健康)


2
我理解你的观点并基本上同意,但听说平均每部iPhone(包括支持其使用的网站/服务)一年使用的能量与美国普通家庭冰箱相当。因此,作为开发人员,我们有责任考虑这种环境影响。显然,这总是一个权衡:时间、成本、性能、稳定性,我基本上同意你的观点,但认为我们也应该考虑这种影响。显然,维护/可扩展性也在其中。无论如何,谢谢你提出这个观点。 - MemeDeveloper
请注意,这个具体问题是关于设备上的处理而不是网络上的处理,但我的评论意在强调开发者应该优先考虑的事项,而不是OP的具体情况。 - MemeDeveloper

11
主要原因是嵌套权重不好的原因在于当一个布局有带权重的子项时,它必须被测量两次(我认为这在lint警告中提到过)。这意味着一个带权重的布局也包含一个带权重的布局,需要测量四次,并且每增加一层权重,测量次数就会增加2的幂次方。
在ICS(API级别14)中,GridLayout 被添加,它允许简单和“扁平”的解决方案来解决以前需要使用权重的许多布局问题。如果您正在开发早期版本的Android,则删除权重可能会更加困难,但使用 RelativeLayout 并尽可能地将您的布局展平可以消除大部分嵌套权重。

9
我认为你无法通过GridLayout或者RelativeLayout来获得相同的结果。比如对于GridLayout,它并不支持所谓的“权重”概念,也就是不能让多个组件共享多余的空间。 - Timmmm
从API 21开始,GridLayout中添加了weight的概念。为了支持旧版Android设备,可以使用来自v7支持库的GridLayout。android.support.v7.widget.GridLayout - Sergei S

3

避免使用嵌套LinearLayout和权重的简单方法是使用Tablelayout和带有权重和内部LinearLayout - Tablelayout具有与LinearLayout相同的属性(方向,权重总和,layout_weight等),不会显示“嵌套权重对性能不好”的消息。

例如:

 <TableLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:weightSum="1">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.8"/>


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="0.2"
            android:orientation="horizontal"
            android:weightSum="1">


            <ImageView
                android:layout_height="match_parent"
                android:layout_width="0dp"
                android:layout_weight="0.4"/>

            <TextView
                android:layout_height="match_parent"
                android:layout_width="0dp"
                android:layout_weight="0.6"/>


            </LinearLayout>

    </TableLayout>

1

我认为,唯一的选择是创建一个名为onResume的函数,并设置所有大小和位置。无论如何,通过权重,您只能设置大小,但不能设置填充(因此布局变得更加复杂),也不能设置文本大小(无法以某种方式补偿此问题),更不用说诸如行数之类的东西了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接