Android ConstraintLayout性能分析

这篇文件是讲述ConstraintLayout性能的分析,如果对于使用ConstraintLayout不是很了解的情况下,请查看Android ConstraintLayout完全解析和性能分析(章节一)Android ConstraintLayout完全解析和性能分析(章节二)。如果对ConstraintLayout使用有一定的掌握,只是想对ConstraintLayout性能进行了解,那我们就开始放飞自我吧。

一、Android 如何绘制视图?

为了更好地理解 ConstraintLayout 的性能,我们先回过头来看看 Android 如何绘制视图。当用户将某个 Android 视图作为焦点时,Android 框架会指示该视图进行自我绘制。这个绘制过程包括 3 个阶段:

  • 1、测量
    系统自顶向下遍历视图树,以确定每个 ViewGroup 和 View 元素应当有多大。在测量 ViewGroup 的同时也会测量其子对象。

  • 2、布局
    系统执行另一个自顶向下的遍历操作,每个 ViewGroup 都根据测量阶段中所确定的大小来确定其子对象的位置。

  • 3、 绘制
    系统再次执行一个自顶向下的遍历操作。对于视图树中的每个对象,系统会为其创建一个 Canvas 对象,以便向 GPU 发送一个绘制命令列表。这些命令包含系统在前面 2 个阶段中确定的 ViewGroup 和 View 对象的大小和位置。

大概流程如下:
在这里插入图片描述
绘制过程中的每个阶段都需要对视图树执行一次自顶向下的遍历操作。因此,视图层次结构中嵌入(或嵌套)的视图越多,设备绘制视图所需的时间和计算功耗也就越多。通过在 Android 应用布局中保持扁平的层次结构,您可以为应用创建响应快速而灵敏的界面。

二、传统布局和ConstraintLayout对比(没有对比,就不知道伤害)

我们会通过布局层级内存占用测量性能这几个方面对比传统布局(RelativeLayout和LinearLayout)和ConstraintLayout。

1、测试环境

  • 手机机型:OPPO F7
  • 系统版本:8.1.0
  • ConstraintLayout版本:1.1.3

2、展示效果图

在日常开发中,为了实现设计师的效果,在传统布局中程序猿常规的做法会通过各种布局的组合以实现设计师的效果图。如下图,在开发中也是经常使用的布局,那我们以此布局做基础,展示不同维度的对比。

3、布局层级对比

  • 传统布局
    在传统布局中,要构建上图布局时,通常会使用RelativeLayout和LinearLayout的组合,xml文件类似下面的层级元素:
<RelativeLayout> 
  <ImageView/>  
  <LinearLayout> 
    <TextView/>  
    <TextView/> 
  </LinearLayout>  
  <LinearLayout> 
    <TextView/>  
    <TextView/> 
  </LinearLayout>  
  <ImageView/>  
  <ImageView/>  
  <LinearLayout> 
    <ImageView/>  
    <LinearLayout> 
      <TextView/>  
      <TextView/> 
    </LinearLayout>  
    <ImageView/> 
  </LinearLayout> 
</RelativeLayout>

尽管一般来说,这种类型的视图层次结构都有改进的空间,但你几乎必定还需要创建一个包含一些嵌套视图的层次结构。

然后在通过View Hierarchy查看实际的布局层级,通过观察可知最深的可达9层
在这里插入图片描述

  • ConstraintLayout布局
    如果通过ConstraintLayout在构建上图时,就显得异常简单了,xml文件类似下面层级元素:
<android.support.constraint.ConstraintLayout >
    <ImageView/>
    <TextView/>
    <TextView/>
    <TextView/>
    <TextView/>
    <ImageView/>
    <ImageView/>
    <ImageView/>
    <TextView/>
    <TextView/>
    <ImageView/>
</android.support.constraint.ConstraintLayout>

是不是感觉布局简单多了,而且也没有出现嵌套的情况。

然后在通过View Hierarchy查看实际的布局层级,通过观察可知最深也就7层
在这里插入图片描述

通过对比可知,在构建相同的上图布局情况下,传统布局比ConstraintLayout多了2层。如前所述,嵌套的层次结构会给性能造成负面影响。

4、内存占用对比

这里我们要对比App运行时内存占用的情况,还是基于构造上图布局做的对比

  • 传统布局
    内存使用情况,从图中可知Graphics占内存使用情况基本在34.3MB左右
    在这里插入图片描述

  • ConstraintLayout
    内存使用情况,从图中可知Graphics占内存使用情况基本在29.5MB左右
    在这里插入图片描述

通过内存使用对比,发现在构建相同效果的布局时,传统布局要比ConstraintLayout要多占不少的内存。其实这个结论由布局层级对比来看,就能预测到这个结果。

5、测量性能对比

我们使用 Android 7.0(API 级别 24)中引入的 OnFrameMetricsAvailableListener 分析了 ConstraintLayout 和 RelativeLayout 这两种类型的布局所执行的每次测量和布局操作所花费的时间。通过该类,您可以收集有关应用界面渲染的逐帧时间信息。 通过调用以下代码,你可以开始记录每个帧的界面操作:

window.addOnFrameMetricsAvailableListener(
        frameMetricsAvailableListener, frameMetricsHandler);

在能够获取时间信息之后,该应用触发 frameMetricsAvailableListener() 回调。我们对测量/布局的性能感兴趣,因此,我们在检索实际帧的持续时间时调用了 FrameMetrics.LAYOUT_MEASURE_DURATION。

 getWindow().addOnFrameMetricsAvailableListener(new Window.OnFrameMetricsAvailableListener() {
            @Override
            public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCountSinceLastInvocation) {
                long layoutMeasureDurationNs =
                        frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION);
                long DRAWDurationNs =
                        frameMetrics.getMetric(FrameMetrics.DRAW_DURATION);

                Log.d("gaozhongkui", "测量耗时:" + layoutMeasureDurationNs + "  绘制耗时:" + DRAWDurationNs);
            }
        }, new Handler());

在相同环境下,通过比较传统布局和ConstraintLayout反复测试4次,得出性能比较结果:ConstraintLayout 在测量/布局阶段的性能比 RelativeLayout大约高 20%:
在这里插入图片描述

这些结果表明:ConstraintLayout 很可能比传统布局的性能更出色。不仅如此,ConstraintLayout 还具备其他一些功能,能够帮助您构建复杂的高性能布局。

三、总结

通过一系列的对比,我们可以得出ConstraintLayout是优于传统布局,无论是从性能、内存占用等等方面吧。但是ConstraintLayout不太适合xml编写,比较适合鼠标拖拽,即所见即所得,不过这样是我们希望的结果。所以建议你在设计应用布局时使用 ConstraintLayout。在过去,几乎所有情形下,您都需要一个深度嵌套的布局,因此,ConstraintLayout 应当成为您优化性能和易用性的不二之选。

发布了20 篇原创文章 · 获赞 30 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_37618354/article/details/84616351