理解ConstraintLayout 对性能的好处

自从在17年GoogleI/O大会宣布了Constraintlayout,我们持续提升了布局的稳定性和布局编辑的支持。我们还为ConstraintLayout添加了一些新特性支持创建不同类型的布局,添加这些新特性,可以明显的提升性能,在这里,我门将讨论ContrainLayout是如何提升性能的。

Android是怎么绘制view的

为了更好的理解constrainLayout 的性能,我们先回顾android是怎么绘制视图的。
当一个用户把一个视图呈现在眼前,android framework 直接让视图绘制自己,绘制的过程包括三个阶段:

  1. measure
    系统完成视图树的自顶向下遍历,以确定每个ViewGroup和View元素应该有多大。 当一个ViewGroup被测量时,它也测量它的子项。

  2. Layout
    另一个自上而下遍历行为,每个ViewGroup使用在测量阶段确定的大小来确定其子级的位置。

  3. Draw
    系统执行另一个自上而下的遍历。 对于视图树中的每个对象,都会创建一个Canvas对象,以向GPU显示绘图命令列表。 这些命令包括ViewGroup和View对象的大小和位置,系统在前两个阶段确定的。

这里写图片描述

绘图过程中的每个阶段都需要对视图树进行自顶向下的遍历。 因此,嵌入到视图层次结构中的视图越多,设备绘制视图所需的时间和计算能力就越多。 通过在您的Android应用布局中保持扁平的层次结构,您可以为您的应用创建快速响应的用户界面。

传统布局结构的开销
为了对着这个观点的说明,让我们创建一个使用LinearLayout和RelativeLayout对象的传统布局层次结构。

这里写图片描述

当我们想实现上面的界面,如果我们使用传统布局,XML布局文件包含下面的元素等级

<RelativeLayout>
  <ImageView />
  <ImageView />
  <RelativeLayout>
    <TextView />
    <LinearLayout>
      <TextView />
      <RelativeLayout>
        <EditText />
      </RelativeLayout>
    </LinearLayout>
    <LinearLayout>
      <TextView />
      <RelativeLayout>
        <EditText />
      </RelativeLayout>
    </LinearLayout>
    <TextView />
  </RelativeLayout>
  <LinearLayout >
    <Button />
    <Button />
  </LinearLayout>
</RelativeLayout>

尽管在这种类型的视图层次结构中通常有改进的空间,但您几乎可以肯定仍然需要使用一些嵌套的视图创建一个层次结构。

如前所述,嵌套层次结构可能会对性能产生不利影响。 让我们使用Android Studio的Systrace工具来看看嵌套视图如何实际影响UI性能。 我们以编程方式调用每个ViewGroup(ConstraintLayout和RelativeLayout)的度量和布局阶段,并在度量和布局调用执行时触发Systrace。 以下命令会生成一个概览文件,其中包含20秒间隔内发生的关键事件(例如,昂贵的度量/布局传递):

python $ANDROID_HOME/platform-tools/systrace/systrace.py --time=20 -o ~/trace.html gfx view res

Systrace会自动突出显示此布局的(许多)性能问题,以及修复这些问题的建议。 通过点击“警报”选项卡,您会发现绘制该视图层次结构需要80个昂贵的测量和布局阶段!

触发许多昂贵的措施和布局阶段是不是很理想; 如此大量的绘图活动可能导致用户注意到的跳帧。 我们可以得出这样的结论:由于嵌套层次结构会导致布局性能较差,像RelativeLayout每次会测量子节点两次。

这里写图片描述

ConstraintLayout 对象的好处

如果你使用ConstrainLayout 去创建相同的布局,XML文件会包含下面的元素架构.

<android.support.constraint.ConstraintLayout>
  <ImageView />
  <ImageView />
  <TextView />
  <EditText />
  <TextView />
  <TextView />
  <EditText />
  <Button />
  <Button />
  <TextView />
</android.support.constraint.ConstraintLayout>

如本例所示,布局现在具有完全平坦的层次结构。 这是因为ConstraintLayout允许您构建复杂的布局,而不必嵌套View和ViewGroup元素。

举个例子:我们看一下当一个TextView和一个EditText在一个布局的中间。

这里写图片描述
当我们使用RelativeLayout, 你需要创建一个新的ViewGroup来使EditText和TextView垂直对齐:

<LinearLayout
    android:id="@+id/camera_area"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:layout_below="@id/title" >

    <TextView
        android:text="@string/camera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:id="@+id/cameraLabel"
        android:labelFor="@+id/cameraType"
        android:layout_marginStart="16dp" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/cameraType"
            android:ems="10"
            android:inputType="textPersonName"
            android:text="@string/camera_value"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginTop="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginEnd="8dp" />
    </RelativeLayout>
</LinearLayout>

通过使用ConstraintLayout来代替,只需从TextView的基线向EditText的基线添加一个约束而不创建另一个ViewGroup即可达到相同的效果:

这里写图片描述

<TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      app:layout_constraintLeft_creator="1"
      app:layout_constraintBaseline_creator="1"
    app:layout_constraintLeft_toLeftOf="@+id/activity_main_done"
app:layout_constraintBaseline_toBaselineOf="@+id/cameraType" />

在使用ConstraintLayout的布局版本上运行Systrace工具时,您会看到在相同的20秒间隔内,测量/布局合格率要低得多。 性能的改善是有意义的,现在我们保持视图层次平坦!

这里写图片描述

在相关说明中,我们仅使用布局编辑器构建了布局的ConstraintLayout变体,而不是手动编辑XML。 为了使用RelativeLayout实现相同的视觉效果,我们可能需要手动编辑XML。

Measuring 的性能不同

我们通过使用Android 7.0(API级别24)中引入的OnFrameMetricsAvailableListener,分析了每种度量和布局通过两种类型的布局ConstraintLayout和RelativeLayout所花费的时间。 此类允许您收集关于应用UI渲染的逐帧时间信息。

通过调用以下代码,您可以开始记录每帧UI操作:

window.addOnFrameMetricsAvailableListener(
        frameMetricsAvailableListener, frameMetricsHandler);

定时信息变为可用后,应用程序将触发frameMetricsAvailableListener()回调。 我们对度量/布局性能感兴趣,因此在检索实际帧持续时间时我们调用FrameMetrics.LAYOUT_MEASURE_DURATION。

Window.OnFrameMetricsAvailableListener {
        _, frameMetrics, _ ->
        val frameMetricsCopy = FrameMetrics(frameMetrics);
        // Layout measure duration in nanoseconds
        val layoutMeasureDurationNs = 
                frameMetricsCopy.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION);

要了解有关FrameMetrics可以接收的其他类型的持续时间信息的更多信息,请参阅FrameMetrics API参考。

测试结果:ConstraintLayout is faster
我们的性能比较显示,ConstraintLayout在度量/布局阶段比RelativeLayout好40%左右:

这里写图片描述

正如这些结果所示,ConstraintLayout可能比传统布局更具性能。 此外,ConstraintLayout还有其他一些功能可以帮助您构建复杂和高性能的布局,正如在ConstraintLayout对象部分中所讨论的。 有关详细信息,请参阅使用ConstraintLayout指南构建响应式UI。 我们建议您在设计应用程序的布局时使用ConstraintLayout。 几乎在所有情况下,如果以前需要深度嵌套的布局,ConstraintLayout应该是您的最佳布局,以实现最佳性能和易用性。

附录:测量环境
以上所有测量均在以下环境中进行。

deviceNexus 5X
android version8.0
contraintLayout version1.0.2
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值