提到防止页面卡顿,大家首先想到的会是页面层级嵌套过多导致过度绘制。那么达到什么程度页面才算过度绘制呢?
绘制限制
手机屏幕由很多像素点组成,通过变换每个像素点的颜色,形成各种各样的图像。GPU控制的一块缓冲区中,这块缓冲区叫做Frame Buffer(也就是帧缓冲区)。可以简单理解成一个二维数组,数组中的每一个元素对应着手机屏幕上的一个像素点,元素的值代表着屏幕上对应的像素点要显示的颜色。优化屏幕画面不断变化,需要这个buffer不断地更新数据,一个FrameBuffer肯定是应接不暇的,因此GPU除了Frame Buffer,用以交给手机屏幕进行绘制外,还有一个缓冲区,叫Back Buffer,这个Back Buffer 用以交给你的应用,让你往里面填充数据。GPU会定期交换Back Buffer和Frame Buffer,也就是让Back Buffer 变成Frame Buffer交给屏幕进行绘制,让原先的Frame Buffer变成Back Buffer交给你的应用进行绘制。交换的频率也是60次/秒,这就与屏幕硬件电路的刷新频率保持了同步。
上面说了刷新频率是1000/60hz = 16ms,这就要求CPU和GPU每秒要有处理60帧的能力,一帧花费的时间在16ms内。因此屏幕刷新的全部逻辑操作也需要在16ms内完成,否则就会出现画面丢失造成卡顿。
CPU过度绘制
指屏幕上的一个像素被绘制多次(超过一次) 但是用户看到的只有最顶层绘制的内容
(1)蓝色1x过度绘制
(2)绿色2x过度绘制
(3)淡红色3x过度绘制
(4)红色4x过度绘制(4次及以上)
App的验收标准:
(1)控制过度绘制为2x
(2)非强制GPU的情况下,无红色区域,即无4x过度绘制情况
(3)浅红色区域总面积不超过屏幕的1/4大小
检测工具
开发者选项->调试GPU过度绘制
关于误解
大家都知道复杂布局的过度嵌套如LinearLayout嵌套过多层的LinearLayout就会导致过度绘制真的是这样吗?
多层嵌套pk无嵌套
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="50dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="50dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="50dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/album_camera_icom" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="多层嵌套"
android:textColor="@color/black"
android:textSize="22sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/album_camera_icom" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="无嵌套"
android:textColor="@color/black"
android:textSize="22sp"
android:textStyle="bold" />
</LinearLayout>
经过手机自带GPU过度绘制检测运行结果如上图,可以看出两者并无差异,那么是什么使它们产生差异呢。下面我们分别为上述LinearLayout添加背景色。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
android:padding="50dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
android:padding="50dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/white"
android:orientation="vertical"
android:padding="50dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/album_camera_icom" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="多层嵌套"
android:textColor="@color/black"
android:textSize="22sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/album_camera_icom" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="无嵌套"
android:textColor="@color/black"
android:textSize="22sp"
android:textStyle="bold" />
</LinearLayout>
当给每一个LinearLayout添加背景色时多层嵌套出现了明显的过度绘制情况。
总结
1.多层嵌套未必会导致GPU过度绘制。
2.GPU过度绘制有一种必然是页面多层嵌套。
3.导致GPU过度绘制产生是一个像素多次绘制,要想避免这种情况添加背景需谨慎。
4.多用ConstraintLayout减少层级嵌套。