UI 抖动检测

Android 通过从您的应用程序生成帧并在屏幕上显示它来呈现 UI。如果您的应用程序出现 UI 渲染缓慢问题,则系统将被迫跳过帧。发生这种情况时,用户会在屏幕上看到反复闪烁,这被称为*抖动*。

当出现卡顿时,通常是由于 UI 线程上的某些减速或阻塞异步调用(在大多数应用程序中,它是主线程)引起的。您可以使用系统跟踪来确定问题所在。

在 Android 12 及更高版本上检测卡顿

对于使用 Android 12(API 级别 31)或更高版本的设备,捕获的跟踪将显示在 CPU 分析器中“显示”窗格下的“卡顿帧”轨道中。

要检测卡顿,

  1. 在 Android Studio 中,选择“视图”>“工具窗口”>“分析器”,或点击工具栏中的“分析”

    如果“选择部署目标”对话框提示,请选择要部署应用程序以进行分析的设备。如果您已通过 USB 连接设备但未看到其列出,请确保已启用 USB 调试

  2. 点击“CPU”时间线中的任意位置以打开 CPU 分析器。

  3. 从 CPU 分析器中的配置菜单中选择“系统跟踪”,然后点击“记录”。在您完成与应用程序的交互后,点击“停止”。

  4. 您应该在“显示”下看到“卡顿帧”轨道。默认情况下,分析器仅将卡顿帧显示为调查候选。在每个卡顿帧中,红色部分突出显示了帧超过其渲染截止时间所花费的持续时间。 卡顿帧轨道截图

  5. 找到卡顿帧后,点击它;可选地,您可以按“M”以调整缩放以将焦点集中在所选帧上。相关事件将在这几个线程中突出显示:主线程、RenderThreadGPU 完成显示卡顿帧和主线程的分析器截图

  6. 您可以选择查看所有帧,或通过分别切换“所有帧”和“生命周期”复选框来查看渲染时间的细分。 与上面相同但选中了“所有帧”和“生命周期”复选框的分析器截图

在 Android 11 上检测卡顿

对于使用 Android 11(API 级别 30)的设备,捕获的跟踪将显示在 CPU 分析器中的“帧生命周期”部分中。

Frame Lifecycle section with different tracks

“帧生命周期”部分包含图层名称和四个轨道。每个轨道代表帧渲染管道中的一个阶段。“帧生命周期”元素如下

  1. 帧生命周期(图层名称):部分标题包含括号中的图层名称。图层是合成的一个单元。
  2. 应用程序:此轨道显示从应用程序排队缓冲区到将其重新排队的持续时间。这通常对应于 RenderThread 中的跟踪事件。
  3. 等待 GPU:此轨道显示缓冲区由 GPU 拥有的时间长度。这是从缓冲区被发送到 GPU 到 GPU 完成对缓冲区的处理的时间。这并不意味着 GPU 在此期间仅处理此缓冲区。有关 GPU 在给定时间处理内容的详细信息,您可能需要使用Android GPU 检查器
  4. 合成:此轨道显示从 SurfaceFlinger 钩住缓冲区并将其发送以进行合成开始的时间到将缓冲区发送到显示器的时间。
  5. 显示上的帧:此轨道显示帧在屏幕上的持续时间。

“帧生命周期”部分说明了帧缓冲区如何在渲染管道的不同阶段之间移动。帧按帧号颜色编码,以便更轻松地跟踪特定帧。

Android Studio 还以表格格式在“所有帧”选项卡中显示跟踪中的所有帧。

A table of all the frames in the trace in the All Frames tab

“帧编号”、“应用程序”、“等待 GPU”和“合成”列代表与上面“帧生命周期”部分中的轨道相同的数据。“帧持续时间”列代表从“应用程序”开始到“显示上的帧”开始的时间。这本质上是渲染一个帧端到端所花费的时间。

您可以按任何列对帧表进行排序,以快速找到最短或最长的帧。该表还支持分页控件,帮助您浏览数百个帧。

要检测和调查 Android 11 上的卡顿,请执行以下步骤

  1. 按降序对“所有帧”表中的“应用程序”列进行排序,以便最长的帧首先出现。

    Application column sorted in descending order

  2. 找到运行时间最长的帧并选择该表行。这会在左侧时间线视图中放大所选帧。

    Timeline view alongside Frames table

  3. 在“帧生命周期”和“线程”部分中查找相关线程。

    Frame Lifecycle and Threads sections

在 Android 10 及更低版本上检测卡顿

对于使用 Android 10(API 级别 29)或更低版本的设备,相关操作系统图形管道信息将显示在 CPU 分析器系统跟踪上的单个部分中,称为“显示”。

The display UI window

  • :此部分显示应用程序中的 UI 线程和 RenderThread 跟踪事件。超过 16 毫秒的事件将用红色着色,以突出显示潜在的卡顿帧,因为它们超过了以每秒 60 帧 (fps) 的速率渲染的截止时间。
  • SurfaceFlinger:此部分显示 SurfaceFlinger 处理帧缓冲区的时间。SurfaceFlinger 是一个系统进程,负责将缓冲区发送到显示器。
  • VSYNC:此部分显示 VSYNC,一个同步显示管道的信号。该轨道显示 VSYNC-应用程序信号,该信号显示应用程序何时开始过晚。通常,这是因为 UI 线程很忙。这会导致动画期间在屏幕上出现可见的闪烁,并在动画或滚动完成之前增加额外的输入延迟。这对于高刷新率显示器尤其重要,因为它们可能比每秒 60 次更频繁地发生,或者以可变速率发生。
  • BufferQueue:此部分显示有多少帧缓冲区已排队并正在等待 SurfaceFlinger 使用。对于部署到运行 Android 9(API 级别 28)或更高版本的设备的应用程序,此轨道显示应用程序表面的缓冲区计数 BufferQueue (012)。BufferQueue 可以帮助您了解图像缓冲区在 Android 图形组件之间移动时的状态。例如,值 2 表示应用程序当前处于三倍缓冲状态,这会导致额外的输入延迟。

“显示”部分提供了有用的信号来检测潜在的卡顿 - 例如,当 UI 线程或 RenderThread 耗时超过 16 毫秒时。要调查导致卡顿的确切细节,您可以探测“线程”部分,该部分显示与 UI 渲染相关的线程。

The Threads section under Display

在上图中,“线程”部分显示 UI 线程 (java.com.google.samples.apps.iosched)、RenderThreadGPU 完成 线程。这些是与 UI 渲染相关的线程,并且可能导致卡顿。

要检测 Android 10 或更低版本上的卡顿,请执行以下步骤

  1. 查看“显示”中的“帧”轨道。红色的帧是调查的候选对象。

    The Frames section under Display

  2. 找到可能出现卡顿的帧后,按 W 或在按住 Control (Command 在 macOS 上) 的情况下滚动鼠标滚轮进行放大。继续放大,直到您开始在 UI 线程和 RenderThread 中看到跟踪事件。

    Trace events in the UI thread and RenderThread

    在上图中,Choreographer#doFrame 显示 UI 线程何时调用 Choreographer 以协调动画、视图布局、图像绘制和相关过程。 DrawFrames 显示 RenderThread 何时形成并向 GPU 发布实际的绘制命令。

  3. 如果您看到一个特别长的跟踪事件,您可以进一步放大并找出可能导致渲染缓慢的原因。上图显示了 UI 线程中的 inflate,这意味着应用程序正在花费时间来膨胀布局。当您放大其中一个 inflate 事件时,您可以确切地找出每个 UI 组件花费的时间,如下所示。

    Menu showing precise duration of a UI component

了解更多

要了解有关如何减少卡顿的更多信息,请参阅卡顿的常见来源