渲染优化

文章来源:
http://wuxiaolong.me/2017/03/26/Rendering/
https://www.jianshu.com/p/989ce9eb7af8
hz:每秒刷新的次数

著名的“16ms”原则:
我们通常都会提到60fps(Frame Per Second)与16ms,可是知道为何会是以程序是否达到60fps来作为App性能的衡量标准吗?
60fps:人眼与大脑之间的协作无法感知超过60fps的画面更新。
*16ms:因为Android设定的刷新率是60fps,也就是每秒60帧,即16ms=1000/60Hz
Android系统每隔16ms会发出VSYNC信号重绘我们的界面。

就像这样:


渲染优化_第1张图片
image.png

如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面。


渲染优化_第2张图片
image.png

Overdraw(过度绘制)是指系统在单个渲染帧中多次绘制屏幕上的像素。例如,如果我们有一堆堆叠的UI卡,不可见的UI也在做绘制的操作,这样会浪费大量的CPU和GPU资源。
渲染操作通常依赖于两个核心组件:CPU与GPU。CPU负责包括Measure,Layout,Record,Execute的计算操作,GPU负责Rasterization(栅格化)操作

如何检测?

  • Show GPU Overdraw
    设置 -> 开发者选项 -> 调试GPU过度绘制 ->显示过度绘制区域。
    对比一张Overdraw的参考图,分别有蓝色,淡绿,淡红,深红代表了4种不同程度的Overdraw情况:


    渲染优化_第3张图片
    image.png

    蓝色,淡绿,淡红,深红代表了4种不同程度的Overdraw情况,我们的目标就是尽量减少红色Overdraw,看到更多的蓝色区域。

Overdraw有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的重叠背景。例如某个Activity有一个背景,然后里面的Layout又有自己的背景,同时子View又分别有自己的背景。仅仅是通过移除非必须的背景图片,这就能够减少大量的红色Overdraw区域,增加蓝色区域的占比。这一措施能够显著提升程序性能。

  • Profile GPU Rendering
    打开Profile GPU Rendering,显示每帧画面所需要渲染的时间。
    设置 -> 开发者选项 -> GPU呈现模式分析 -> 在屏幕上显示为条形图
渲染优化_第4张图片
image.png

界面上会滚动显示垂直的柱状图来表示每帧画面所需要渲染的时间,柱状图越高表示花费的渲染时间越长。中间有一根绿色的横线,代表16ms,我们需要确保每一帧花费的总时间都低于这条横线,这样才能够避免出现卡顿的问题。

  • Hierarchy Viewer
    用Hierarchy Viewer工具检查Activity中的布局是否过于复杂
    Tools -> Android -> Android Device Monitor。


    渲染优化_第5张图片
    image.png

    渲染优化_第6张图片
    image.png
渲染优化_第7张图片
image.png

其实中带有红色或黄色的点代表速度较慢的View。

优化方案:

  • 删除布局中不必要的背景属性
  • 尽量减少布局的层级
    来源:https://blog.csdn.net/xyz_lmn/article/details/14524567
    减少视图层级
    标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。多用于替换FrameLayout或者当一个布局包含另一个时,标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用标签优化。

 
    

现在,当你添加该布局文件时(使用标签),系统忽略节点并且直接添加两个Button。

  • 需要时使用
    标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用标签,以减少内存使用量,加快渲染速度。是一个不可见的,大小为0的View。标签使用如下:


当你想加载布局时,可以使用下面其中一种方法:


((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();

当调用inflate()函数的时候,ViewStub被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数findViewById()来查找了。
注:ViewStub目前有个缺陷就是还不支持 标签。

你可能感兴趣的:(渲染优化)