ConstraintLayout真的就那么强?拉出来比一比!

6,277 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情

ConstraintLayout 性能对比与分析

关于 ConstraintLayout 的介绍就不用多说了吧,到今天来说已经是基本控件了,如果真有不会用的看官网介绍。

现在感觉大家都已经有点神话 ConstraintLayout 了,现在创建 Activity 的 xml 。默认的根布局就是 ConstraintLayout 了,咋滴,真要我们把全部页面都用一个 ConstraintLayout 包裹吗?

百度搜索一下 ConstraintLayout 。全是优化布局!!!

我心里打个问号?真有这么强?ConstraintLayout 就无敌了?

这里我用 LinearLayout RelativeLayout ConstraintLayout 做一个对比,实现同样的效果,三种布局分别来实现,看看耗时多少!

耗时方法统计为 设置布局之前与展示布局之后。

    override fun onCreate(savedInstanceState: Bundle?) {
        start = System.currentTimeMillis()

        super.onCreate(savedInstanceState)
    }

    override fun onResume() {
        super.onResume()
        end = System.currentTimeMillis()

        YYLogUtils.w("耗时:" + (end - start))
    }

一、简单布局测试

实现一个简单的2行文本

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="@dimen/d_15dp"
    android:paddingBottom="@dimen/d_15dp"
    tools:background="@color/white">


    <TextView
        android:id="@+id/tv_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="君不见," />


    <TextView
        android:id="@+id/tv_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="黄河之水天上来" />


    <TextView
        android:id="@+id/tv_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="奔流到海不复回" />


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_1"
        android:layout_marginTop="@dimen/d_10dp"
        android:text="君不见" />


    <TextView
        android:layout_below="@id/tv_1"
        android:layout_marginTop="@dimen/d_10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="高堂明镜悲白发" />


    <TextView
        android:layout_below="@id/tv_1"
        android:layout_marginTop="@dimen/d_10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="朝如青丝暮成雪" />

</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="@dimen/d_15dp"
    android:paddingBottom="@dimen/d_15dp"
    tools:background="@color/white">

    <TextView
        android:id="@+id/tv_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="君不见,"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/tv_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="黄河之水天上来"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/tv_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="奔流到海不复回"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <TextView
        android:id="@+id/tv_4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/d_10dp"
        android:layout_weight="1"
        android:text="君不见,"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/tv_1" />


    <TextView
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@id/tv_4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="高堂明镜悲白发" />


    <TextView
        app:layout_constraintTop_toTopOf="@id/tv_4"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="right"
        android:text="朝如青丝暮成雪" />

</androidx.constraintlayout.widget.ConstraintLayout>

结果:

LinearLayoutRelativeLayoutConstraintLayout
535361
575454
525354
515259
526253
535953

结果是简单布局实现 LinearLayout 更优秀。RelativeLayout 和 ConstraintLayout 的 区别不大。

二、稍微复杂布局测试

实现的效果如下:

这里我们就不贴重复的代码了,实现的方式与上面类似。同样的效果只是多添加几层,看看实现的结果。

LinearLayoutRelativeLayoutConstraintLayout
838385
858187
868493
838385
998184
868286

稍微复杂的布局中,,确实 RelativeLayout 和 ConstraintLayout 这种布局实现减少层级之后确实展示的更快了。LinearLayout 已经没有优势了!但是这里 RelativeLayout 的要比 ConstraintLayout 强一点!

话不多说,我们看看比较复杂的布局测试。

三、比较复杂布局测试

实现效果如下:

一共14行布局,我们就不贴重复的代码了,实现的方式与上面类似。都是很基本的实现方式了,我们直接看看结果。

LinearLayoutRelativeLayoutConstraintLayout
140162156
140144163
150155165
142144159
140147152
153150161

可以看到在比较复杂的布局中,LinearLayout 又赶超上来了,这里 RelativeLayout 与 ConstraintLayout 的性能差不多了。

可以看到在比较复杂的布局中还是不太推荐 全部一个 ConstraintLayout 包裹实现。

四、RV列表中的使用

这是静态布局的展示,那么在列表中的使用性能又如何呢?

这里直接上图吧!

ConstraintLayout 的Item布局实现,明显卡顿,都已经超出屏幕外了。后续往回拉动展示缓存布局的时候也会超出16.6ms。 会出现轻微的卡顿。

LinearLayout 的情况与 RelativeLayout 的布局类似,虽然也卡,但是没有那么的明显。后续往回拉动展示缓存布局的时候也明显帧数更低。不会出现卡顿。

为什么出现这种情况。我们看看相同的布局 他们 onMeasure onLayout onDraw的耗时。(注:这里的耗时是纳秒)

Cons01 onMeasure - 27323438
Cons01 onMeasure - 22129271
Cons01 onLayout - 3678230
Cons01 onDraw - 5311458

Rel01 onMeasure - 8344687
Rel01 onMeasure - 1069531
Rel01 onLayout - 2910156
Rel01 onDraw - 4294010

Lin01 onMeasure - 3184948
Lin01 onMeasure - 3351094
Lin01 onLayout - 5469532
Lin01 onDraw - 5566250

每一个布局的展示都是两次onMeasure 一次onLayout 一次onDraw。这都是正常的,因为ViewGroup要先测量子布局再测量自己。

重点是看 ConstraintLayout 的测量耗时,这也太那啥了,ConstraintLayout 测量的耗时为 LinearLayout 的8倍。

五、总结

当前使用的 ConstraintLayout 测试版本为2.0.3 非最新版本,测试机型为7.0老款机型,本人非专业测试,测试工具不专业,当前测试结果仅供参考。

尽管如此,我们还是可以得到大致的结论:

ConstraintLayout 并没有比 RelativeLayout性能好到哪里去。在简单的布局和复杂的布局中 LinearLayout 还是YYDS(比如图片+文本一行的布局)。 在稍微复杂的布局中,我们确实可以通过减少层级优化布局加载数据,此时使用 ConstraintLayout 确实不错(比如Me页面多图片+多文本)。

在复杂的布局中我们可以使用 LinearLayout 作为根视图,内部的每一个稍微复杂的子布局View用ConstraintLayout,这样 LinearLayout + ConstraintLayout 的布局方式,性能比纯ConstraintLayout布局好好一点。

同时在列表中尽量避免使用 ConstraintLayout 做Item的整个根视图,测量会比较耗时。推荐使用 LinearLayout ,或者 LinearLayout + RelativeLayout 的布局方式。

虽然说 ConstraintLayout 的性能并没有爆表,但是 ConstraintLayout 的一些新特效确实太香,比如百分比布局,宽高比例布局适配太方便,比如 ConstraintLayout 中的 MotionLayout 做动画也太方便了趴。在实际开发中的使用场景也是很多的。

最后说明一下,比如同样的布局 LinearLayout 嵌套三层 对比 ConstraintLayout 只有一层,可能他们的性能是相仿的,但是有人喜欢简单的 LinearLayout 有人喜欢去慢慢约束写 ConstraintLayout 。毕竟快那1ms 2ms的没意义。只要在8ms(高刷)-16ms内渲染完成就行了。个人习惯不同而已,没有谁对谁错。

OK,说了这么多,如果大家有不同意见,欢迎到评论区留言哦。

完结了

参考文章:

ConstaintLayout性能分析

ConstraintLayout UI性能分析