1、ConstraintLayout是什么?
废话,当然是布局类型了。以前的布局类型有5种:线性布局、帧布局、相对布局、表格布局、绝对布局,常用的其实也就是前面三种。
ConstraintLayout就是约束布局,就是根据控件与控件之间的约束条件来决定最后在界面上的位置。就好像拼图一样,每一块拼图都跟相邻的拼图有约束关系,而拼图的边和角就直接和相框有约束关系,从而最后组成一幅完整的图画。
2、为什么需要ConstraintLayout?
了解过或者做过布局优化的话,应该都了解,如果布局内的层数越多,越消耗性能。可以看到,要绘制一个界面,就需要在树里面先找到叶子,确定好了叶子的大小和位置,再逐步向上遍历。简单的,也就是递归。所以当布局内的层数越多,那布局的计算也就越复杂。
而ConstraintLayout,就是让所有的布局内的view,都平铺在同一层,从而减少布局内的层数,优化界面的绘制消耗。
3、relativeLayout也可以达到单层布局,ConstraintLayout真的有用?
来试一试,先自定义2个View,分别继承relativeLayout和ConstraintLayout,并统计onMeasure的时间。
<?xml version="1.0" encoding="utf-8"?>
<com.example.test.view.MeasureTimeRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
</com.example.test.view.MeasureTimeRelativeLayout>
这是相对布局的xml文件,我们多次启动,看看界面绘制的耗时:
那再看看ConstraintLayout的耗时:
4、如果层次多一点的界面,耗时怎么样?
<?xml version="1.0" encoding="utf-8"?>
<com.example.test.view.MeasureTimeRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/rl1"
android:layout_width="match_parent"
android:layout_height="300dp">
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/textView2"
android:layout_centerHorizontal="true">
<TextView
..../>
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_below="@id/rl1">
<TextView
..../>
<TextView
..../>
<TextView
... />
<TextView
... />
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<TextView
..../>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/textView22"
android:layout_centerHorizontal="true">
<TextView
..../>
</RelativeLayout>
</RelativeLayout>
</com.example.test.view.MeasureTimeRelativeLayout>
这是RelativeLayout的耗时:那我们为什么还要用ConstraintLayout?
其实,上面的情况是这样,只是因为布局内的元素还算是简单的搭配,但是随着界面的复杂度提升,还有一些view的计算,这时候ConstraintLayout的性能优势就体现出来了。
例如以下几个例子:
①根据中心view,其他view按照角度来定位布局。
后两种已经是常见得不能再常见的需求了,但是如果不使用ConstraintLayout,只使用相对布局或者线性布局来实现,那就只能动态获取相应的文字宽度、图片的大小比例,之后再去计算填充到布局里了。
ConstraintLayout还有很多强大的属性,是其他布局做不到或者很难做到的,感兴趣的可以自行搜索研究。
那ConstraintLayout是怎么做到复杂的布局的性能优化的?
ConstraintLayout 的组成可以大致分为三个部分:ConstraintWidgetContainer,ConstraintWidget 和 Cassowary 算法(全称 The Cassowary Linear Arithmetic Constraint Solving Algorithm,有兴趣的同学可以自行搜索)。
ConstraintWidgetContainer 相当于引擎,ConstraintWidget 是所有 ConstraintLayout 所包含控件的抽象(每个child 对应一个 ConstraintWidget),ConstraintWidgetContainer 驱动 所有 ConstraintWidget 进入 Cassowary算法封装盒子,Cassowary 将计算好的 ConstraintWidget 输出交给 ConstraintWidgetContainer,这时,所有child 的布局数据都已经被计算出来,ConstraintLayout只需要把它们放在数据指示的位置即可。
还记得上面实验计算耗时的结果吗?ConstraintLayout的耗时随着进入界面的次数,是逐步减少的,为什么会这样?
其实这个不是ConstraintLayout干的优化结果,是Android的机制问题。
Android 2.2-4.4:
这部分都是使用JIT,就是说都是在运行的时候,需要用什么,就加载什么,好处就是安装贼快,但缺点也明显,每次运行都需要重新编译,浪费资源,例如电量。
Android L(5.0)- Android N:
安装时直接使用预先编译(AOT),就是把所有代码一次性转化为本地机器码,当需要使用时就可以直接使用了。但是缺点就是第一次安装的时候十分的慢,因为一次性转化全部代码很耗时。
Android N(7.0)以上的:
安装apk的时候,不进行任何的预编译(提高安装速度);
运行的过程中解析执行,并且对经常使用的方法进行优化,就是即时编译(JIT just in time),经过JIT处理的代码,都会记录在一个profile配置文件里;
最后在手机闲的时候,有一个编译守护进程,会对profile里面的方法进行预先编译(AOT),把这些代码转化为本地机器码。
是由于这个原因,使得ConstraintLayout的耗时越来越少的。如果拿几台对应的系统版本手机来测试,你就会发现5.0-N的是耗时最少的,而且耗时不变。而另外2种,耗时都是逐渐减少。
那ConstraintLayout有啥缺点?
纯个人观点:
①要多写点属性
②牵一发而动全身,有时候改一个控件,布局全变了(所以一定要找好作为锚的控件)
③如果界面布局不是很复杂,性能甚至比旧的布局类型还要差
④复杂的界面,所用元素都放在统一平面上,代码的可读性会十分差
总结:
①不要一股脑全用ConstraintLayout,简单的布局,还是其他布局类型较好。
②网上一堆说ConstraintLayout的性能优化,都好像只是说布局的嵌套层数问题,其实并不是,需要看实际情况。
③就算ConstraintLayout能做到全部元素放在统一父布局内,也应该适当地分层