Android 性能优化典范

2,364 阅读8分钟
原文链接: www.csdn.net
摘要:新年伊始,Google发布了包含16个短视频的Android性能优化典范专题,详解Android系统中有关性能问题的底层工作原理,并介绍了如何通过工具找出性能问题以及提升性能的建议。本文作者对这些问题和建议进行了总结梳理。

2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App。课程专题不仅仅介绍了Android系统中有关性能问题的底层工作原理,同时也介绍了如何通过工具来找出性能问题以及提升性能的建议。主要从三个方面展开,Android的渲染机制,内存与GC,电量优化。下面是对这些问题和建议的总结梳理。

系列阅读

  • Android 性能优化典范(一):主要从 Android 的渲染机制、内存与 GC、电量优化三个方面展开,介绍了 Android 中性能问题的底层工作原理,以及如何通过工具来找出性能问题及提升性能的建议。
  • Android 性能优化典范(二):20 个短视频,主要内容为:电量优化、网络优化、Android Wear 上如何做优化、使用对象池来提高效率、LRU Cache、Bitmap 的缩放、缓存、重用、PNG 压缩、自定义 View 的性能、提升设置 alpha 之后 View 的渲染性能,以及 Lint、StictMode 等工具的使用技巧。
  • Android 性能优化典范(三):更高效的 ArrayMap 容器,使用 Android 系统提供的特殊容器来避免自动装箱,避免使用枚举类型,注意onLowMemoryonTrimMemory的回调,避免内存泄漏,高效的位置更新操作,重复 layout 操作的性能影响,以及使用 Batching,Prefetching 优化网络请求,压缩传输数据等使用技巧。
  • Android 性能优化典范(四):优化网络请求的行为,优化安装包的资源文件,优化数据传输的效率,性能优化的几大基础原理等。
  • Android 性能优化典范(五):文章共有10个段落,涉及的内容有:多线程并发的性能问题,介绍了 AsyncTask、HandlerThread、IntentService 与 ThreadPool 分别适合的使用场景以及各自的使用注意事项。这是一篇了解 Android 多线程编程不可多得的基础文章,清楚地了解这些 Android 系统提供的多线程基础组件之间的差异以及优缺点,才能够在项目实战中做出最恰当的选择。
  • Android 性能优化典范(六):文章共 6 个段落,涉及的内容主要有程序启动时间性能优化的三个方面:优化 activity 的创建过程,优化 Application 对象的启动过程,正确使用启动显屏达到优化程序启动性能的目的。另外还介绍了减少安装包大小的 checklist 以及如何使用 VectorDrawable 来减少安装包的大小。


1) Render Performance

大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。从设计师的角度,他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用户体验。但是Android系统很有可能无法及时完成那些复杂的界面渲染操作。Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。


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


用户容易在UI执行动画或者滑动ListView的时候感知到卡顿不流畅,是因为这里的操作相对复杂,容易发生丢帧的现象,从而感觉卡顿。有很多原因可以导致丢帧,也许是因为你的layout太过复杂,无法在16ms内完成渲染,有可能是因为你的UI上有层叠太多的绘制单元,还有可能是因为动画执行的次数过多。这些都会导致CPU或者GPU负载过重。

我们可以通过一些工具来定位问题,比如可以使用HierarchyViewer来查找Activity中的布局是否过于复杂,也可以使用手机设置里面的开发者选项,打开Show GPU Overdraw等选项进行观察。你还可以使用TraceView来观察CPU的执行情况,更加快捷的找到性能瓶颈。

2) Understanding Overdraw

Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制了多次。这就浪费大量的CPU以及GPU资源。


当设计上追求更华丽的视觉效果的时候,我们就容易陷入采用越来越多的层叠组件来实现这种视觉效果的怪圈。这很容易导致大量的性能问题,为了获得最佳的性能,我们必须尽量减少Overdraw的情况发生。

幸运的是,我们可以通过手机设置里面的开发者选项,打开Show GPU Overdraw的选项,可以观察UI上的Overdraw情况。


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

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

3) Understanding VSYNC

为了理解App是如何进行渲染的,我们必须了解手机硬件是如何工作,那么就必须理解什么是VSYNC。

在讲解VSYNC之前,我们需要了解两个相关的概念:

  • Refresh Rate:代表了屏幕在一秒内刷新屏幕的次数,这取决于硬件的固定参数,例如60Hz。
  • Frame Rate:代表了GPU在一秒内绘制操作的帧数,例如30fps,60fps。

GPU会获取图形数据进行渲染,然后硬件负责把渲染后的内容呈现到屏幕上,他们两者不停的进行协作。


不幸的是,刷新频率和帧率并不是总能够保持相同的节奏。如果发生帧率与刷新频率不一致的情况,就会容易出现Tearing的现象(画面上下两部分显示内容发生断裂,来自不同的两帧数据发生重叠)。


理解图像渲染里面的双重与三重缓存机制,这个概念比较复杂,请移步查看Graphics以及《了解Android 4.1之三:黄油项目 —— 运作机理及新鲜玩意》。


通常来说,帧率超过刷新频率只是一种理想的状况,在超过60fps的情况下,GPU所产生的帧数据会因为等待VSYNC的刷新信息而被Hold住,这样能够保持每次刷新都有实际的新的数据可以显示。但是我们遇到更多的情况是帧率小于刷新频率。


在这种情况下,某些帧显示的画面内容就会与上一帧的画面相同。糟糕的事情是,帧率从超过60fps突然掉到60fps以下,这样就会发生LAG,JANK,HITCHING等卡顿掉帧的不顺滑的情况。这也是用户感受不好的原因所在。

4) Tool:Profile GPU Rendering

性能问题如此的麻烦,幸好我们可以有工具来进行调试。打开手机里面的开发者选项,选择Profile GPU Rendering,选中On screen as bars的选项。


选择了这样以后,我们可以在手机画面上看到丰富的GPU绘制图形信息,分别关于StatusBar,NavBar,激活的程序Activity区域的GPU Rending信息。


随着界面的刷新,界面上会滚动显示垂直的柱状图来表示每帧画面所需要渲染的时间,柱状图越高表示花费的渲染时间越长。


中间有一根绿色的横线,代表16ms,我们需要确保每一帧花费的总时间都低于这条横线,这样才能够避免出现卡顿的问题。


每一条柱状线都包含三部分,蓝色代表测量绘制Display List的时间,红色代表OpenGL渲染Display List所需要的时间,黄色代表CPU等待GPU处理的时间。