了解使用ConstraintLayout的性能优势
原标题:Understanding the performance benefits of using ConstraintLayout
链接:https://android-developers.googleblog.com/2017/08/understanding-performance-benefits-of.html
作者:Takeshi Hagikura (开发程序工程师)
翻译:arjinmc
自去年在Google I / O 宣布ConstraintLayout以来,我们一直在不断改进布局的稳定性和布局编辑器支持。我们还给ConstraintLayout添加了特定功能的新功能可以帮助你构建各种类型的布局,例如引入链和设置大小作为比例。除了这些功能之外,还有一个显着的性能优势ConstraintLayout。在这篇文章中,我们将介绍如何从这些性能改进中获益。
Android如何绘制视图?
为了更好地了解性能ConstraintLayout,让我们回顾一下,看看Android如何绘制视图。
当用户将Android视图引入焦点时,Android框架会引导该视图进行绘制。这个绘图过程包括3个阶段:
测量
系统完成视图树的自顶向下遍历,以确定每个ViewGroup和View元素应该有多大。当一个ViewGroup被测量时,它也测量其孩子。布局
发生另一个自上而下的遍历,每个ViewGroup使用在测量阶段确定的大小来确定其孩子的位置。绘制
系统执行另一个自上而下的遍历。对于视图树中的每个对象,Canvas创建一个对象来向GPU发送绘图命令列表。这些命令包括ViewGroup与View对象的大小和位置,其中所述系统在过去2个阶段来确定。
图1.测量阶段如何遍历视图树的示例
绘图过程中的每个阶段需要从视图树的自顶向下遍历。因此,在视图层次结构中彼此嵌套(或嵌套)的视图越多,设备绘制视图所需的时间和计算能力就越多。通过在Android应用程序布局中保持平面的层次结构,你可以为应用程序创建一个快速响应的用户界面。
传统布局层次结构的消耗
考虑到这个解释,让我们创建一个使用传统的布局层次结构LinearLayout和RelativeLayout对象。
图2.布局示例
假设我们要构建一个如上图所示的布局。如果使用传统布局构建XML文件,则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的更多详细信息,请参阅使用Systrace分析UI性能指南。
Systrace自动突出显示了这个布局的(众多)性能问题,以及修复它们的建议。通过单击“Alerts”选项卡,你将发现绘制此视图层次结构需要80个昂贵消耗的通过测量和布局阶段!
触发许多昂贵的测量和布局阶段远非理想; 如此大量的绘图活动可能会导致用户注意到的跳过的框架。我们可以得出结论,由于嵌套的层次结构像RelativeLayout的及其每个孩子两次测量的特点这样的层次结构,布局性能差。
图3.查看Systrace对于使用的布局变体的警报RelativeLayout
你可以在我们的GitHub库中查看有关我们如何执行这些测量的整个代码。
ConstraintLayout对象的好处
如果使用相同的布局创建ConstraintLayout,则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:
图4. EditText和TextView之间的约束
<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" />
在为所使用的版本版本运行Systrace工具时,ConstraintLayout在相同的20秒间隔内,你会看到更少的昂贵的测量/布局传递。这种性能的提高是有道理的,现在我们保持视图层次平坦!
图5.查看Systrace使用的布局变体的警报ConstraintLayout
在相关的说明中,我们ConstraintLayout使用布局编辑器构建了我们的布局,而不是用手编辑XML。为了达到使用相同的视觉效果RelativeLayout,我们可能需要手动编辑XML。
测量性能差异
我们分析每一项措施和布局通多长时间才两点式布局,ConstraintLayout并且RelativeLayout,通过使用OnFrameMetricsAvailableListener,这是在安卓7.0(API级别24)推出。此类可让你收集有关应用程序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更快
我们的性能比较表明,ConstraintLayout进行在测定/布局相比RelativeLayout更好约40%:
图6.测量/布局(单位:ms,平均100帧)
如这些结果所示,ConstraintLayout可能比传统布局更具有性能。此外,ConstraintLayout还有其他功能可以帮助你构建复杂和执行的布局,如ConstraintLayout对象部分的优点的讨论。有关详细信息,请参阅使用ConstraintLayout构建响应式UI指南。我们建议你在设计应用程序的布局时使用ConstraintLayout。在几乎所有情况下,如果你以前需要深入嵌套的布局,则ConstraintLayout应该是你的布局,以获得最佳性能和易用性。
附录:测量环境
上述所有测量均在以下环境中进行。
内容 | 型号 |
---|---|
设备 | Nexus 5X |
Android版本 | 8 |
ConstraintLayout版本 | 1.0.2 |
下一步是什么
查看开发者指南,API参考文档和Medium上的文章,以充分了解ConstraintLayout可为你提供的内容。再次感谢所有提交反馈意见的人士,以及自从我们的alpha版本发布以来的几个月ConstraintLayout。我们衷心感谢,我们能够发布生产就绪版本1.0的ConstraintLayout在今年早些时候。随着我们不断改进ConstraintLayout,请继续使用Android问题跟踪向我们发送反馈。