作为开发人员,我们希望构建不仅美观、功能丰富、而且性能高的移动应用程序。我们经常考虑如何优化网络调用和后台操作,但是用户通常把性能与他们交互的移动应用程序的主要组件等同起来:用户界面。当涉及到UI性能时,流畅的经验通常可以定义为每秒60帧的一致性(fps),这意味着我们要每16毫秒渲染一帧。在这个博客文章中,你将学到一些提示和技巧来识别和调试应用程序的用户界面以获得最高性能。

为什么60 fps?

应用程序动画和转换只是一系列静止的图像或帧。诀窍在于快速地展示这些单独的帧,以诱使人脑思考流体运动正在发生。每秒60帧是平滑运动的甜蜜点,但滴在帧率会明显的人的眼睛,这是更在这个视频中,Colt McAnlis解释说。这使我们的整个帧过程小于16毫秒完全在屏幕上绘制一帧。既然我们知道我们想要实现什么,我们如何确保我们的应用程序满足这个性能要求呢?

确定问题

你曾经有过这样的经历吗?

滚动是非常波涛汹涌的,因此,用户界面似乎不响应用户。During the time that the application is unresponsive and choppy, if the user attempts to interact with the application and it takes longer than 在应用程序没有响应和波动的情况下,如果用户试图与应用程序交互,应用程序需要响应超过5000毫秒(5秒),Android操作系统将给我们这个可爱的消息: for the application to respond, the Android OS will give us this lovely message:

也许你已经在你的日志中看到如下:

I/Choreographer(1200): Skipped 60 frames! The application may be doing too much work on its main thread.

这是Android的编舞警告你提前,你的应用程序不执行与平滑流畅的体验,我们的目标。事实上,它告诉你,你跳过了框架,而不是为你的用户提供60 fps的体验。我们可以做得更好!下面是标识和修复UI性能问题的基本过程:

  • 测量Systrace整体UI性能获得基线。
  • 使用浏览器的层次识别和平坦的视图层次结构。
  • 降低透支的扁平化布局和屏幕上的像素图少。
  • 使StrictMode来识别和减少潜在的阻塞调用在主UI线程。

入门

跳过的帧计数

Android是指这些跳过或推迟其帧帧。在您的应用程序已运行和互动重现其框架,运行以下命令:

adb shell dumpsys gfxinfo [PACKAGE_NAME]

这个命令会输出类似下面:

Stats since: 524615985046231ns
Total frames rendered: 8325
Janky frames: 729 (8.76%)
90th percentile: 13ms
95th percentile: 20ms
99th percentile: 73ms
Number Missed Vsync: 294
Number High input latency: 47
Number Slow UI thread: 502
Number Slow bitmap uploads: 44
Number Slow issue draw commands: 135

数字不会说谎,那么很显然我们有一些janky帧(~ 9%)。让我们深入进一步与Systrace工具。

使用Systrace工具

Systrace给你整个Android系统的概述,并告诉你发生了什么事在特定的时间间隔。

入门

让我们开始我们的设备Systrace。第一个开放的Android设备监控开始。一进去,我们看到选项启动一个Systrace:

12.08.2016-13.30

系统会弹出一个提示询问我们是否开始跟踪。选择常用的用户标签并离开高级选项,反选生成trace.html文件,在我们指定的跟踪期间。

这是一个在30秒内systrace的实例:

jank1

好的!但这都意味着什么呢?让我们一步一步来吧。

我们可以看到我们的警报行中有圆形警告标志标识的警报数量。在我们看的过程中,我们可以看到一排架。框架颜色黄色或红色的是那些超过16毫秒的渲染时间。

单击警报将显示我们跟踪窗口底部的问题概述。我们可以通过单击进程中相关的框架图标或在警报描述中单击框架来深入到特定的框架。这将给我们的时间花在这一步:

最后,你可以标记帧使用M热键和放大到受影响的框架看什么工作正在各个线程完成,如CPU线程,UI线程,和renderthread。

这个例子显示一个黄色的框架,但我们可以得到一个总的想法是一个高性能的框架可能看起来像。

从我们的警觉,我们可以看到,我们要避免在认为有意义的工作。ondraw()或冲。draw(),特别拨款或画了Bitmaps。谷歌给了我们一个提示,在这个视频观看。

我们的框架,我们可以看到,我们的Adapter.Getview()应该创建一个新的循环来查看。

Systrace条款

框架颜色

  • 绿色:伟大的表现
  • 黄色:不太理想的表现
  • 红色:糟糕的表现
调度延迟

当处理特定切片的线程没有在CPU上调度很长时间时,调度延迟就会发生。因此,它需要更长的时间,这个线程的启动和完成。

墙的持续时间

从一片直到完成它开始的时间。

CPU 持续时间

那片时间的CPU在处理量。

Overdraw

透支过度重绘我们的用户界面,导致在一个缓慢的用户界面体验(布局通胀,动画等)。调试透支是相当容易的;我们可以使诊断这在你的Android设备的设置去Settings -> Developer Options -> Debug GPU overdraw -> Show overdraw区域。

一旦启用,你将会看到你的布局,不同的颜色。

  • 白色:没有透支
  • 蓝:那是1x透支像素
  • 绿色:像素是2倍透支
  • 粉红:是3x透支像素
  • 红色:这是4x透支像素

布局性能差:                                                      良好的布局性能:

然后你可以确定为什么这种布局会透支这么多通过工具,如浏览器的层次。

层级观察器

关于视图层次结构,我们首先要知道的是我们的布局有多深或多嵌套。更多的嵌套布局,更多的GPU透支我们通常有。

让我们把坏的布局表现前面的例子:


我们可以看到,我们是四层,这是不理想的ListView中。我们真的需要把这个用户界面了。

好吧,那稍微好一点!我们现在只有三层深。然而,UI性能还不是很大。让我们试着再去掉一层。

更好的!我们优化我们的整体视图层次,将获得的性能优势。让我们看一看整体布局,绘制时间证明。

  • Bad Layout: 31 views / Layout: 0.754 ms / Draw: 7.273 ms
  • Better Layout: 26 views / Layout: 0.474 ms / Draw: 6.191 ms
  • Good Layout: 17 views / Layout: 0.474 ms / Draw: 1.888 ms

StrictMode

StrictMode是一个非常有用的测试你的应用程序的工具。启用StrictMode确保你没有把额外的工作放在你的应用程序中的某个地方,例如磁盘读取、磁盘写入和网络调用,以帮助您提供良好的用户体验。一言以蔽之,StrictMode如下:

  1. 使用 LogCat输出日志消息在StrictMode标签下。
  2. 显示一个对话框 (如果PenaltyLog()是可用的。
  3. 应用程序崩溃时 (如果PenaltyDeath()是可用的)。

这可以帮助你确定你想战斗测试您的应用程序在什么样的政策。

你可以在你的Android应用中启用StrictMode,通过在Activity中添加一些如下的处理:

protected override void OnCreate(Bundle bundle)
{
    StrictMode.SetThreadPolicy(new StrictMode.ThreadPolicy.Builder().DetectAll().PenaltyLog().Build());
    StrictMode.SetVmPolicy(new StrictMode.VmPolicy.Builder().DetectLeakedSqlLiteObjects().DetectLeakedClosableObjects().PenaltyLog().PenaltyDeath().Build());
    base.OnCreate(bundle);
}

结束语

在这篇博客中, 我们介绍了包括Systrace, GPU overdraw, Hierarchy Viewer, 和 StrictMode 在内的一些工具,来处理并修复你的应用中的能问题。通过这些工具的使用,我们可以帮助确保我们提供的Android应用程序,为我们的用户提供优良的渲染性能,实现了平滑流畅的60fps。