UI 卡顿检测

Android 通过生成应用帧并在屏幕上显示来渲染 UI。如果您的应用 UI 渲染缓慢,则系统将被迫跳过帧。发生这种情况时,用户会在屏幕上感知到反复的闪烁,这被称为卡顿

当发生卡顿时,通常是由于 UI 线程(在大多数应用中是主线程)上存在某种减速或阻塞的异步调用。您可以使用系统轨迹来识别问题所在。

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

对于使用 Android 12(API 级别 31)或更高版本的设备,捕获的轨迹会显示在 CPU Profiler 的 Display 窗格下方的 Janky frames 轨迹中。

要检测卡顿,请执行以下操作:

  1. 在 Android Studio 中,选择 View > Tool Windows > Profiler 或点击工具栏中的 Profile 个人资料图标

    如果出现 Select Deployment Target 对话框,请选择要用于分析的应用部署设备。如果您已通过 USB 连接设备但未看到它列出,请确保您已启用 USB 调试

  2. 点击 CPU 时间轴中的任意位置以打开 CPU Profiler。

  3. 从 CPU Profiler 中的配置菜单中选择 System Trace,然后点击 Record。与应用交互完成后,点击 Stop

  4. 您应该会在 Display 下看到 Janky frames 轨迹。默认情况下,Profiler 只会将卡顿帧显示为调查对象。在每个卡顿帧内,红色部分会突出显示帧超出其渲染截止时间的持续时间。卡顿帧轨迹的屏幕截图

  5. 找到一个卡顿帧后,点击它;您可以选择按 M 键调整缩放以聚焦到选定的帧。相关事件会在以下线程中突出显示:主线程、RenderThreadGPU completion显示卡顿帧和主线程的 Profiler 屏幕截图

  6. 您可以通过分别勾选 All FramesLifecycle 复选框来选择查看所有帧或渲染时间的细分。与上方相同但勾选了“所有帧”和“生命周期”复选框的 Profiler 屏幕截图

在 Android 11 上检测卡顿

对于使用 Android 11(API 级别 30)的设备,捕获的轨迹会显示在 CPU Profiler 的 Frame Lifecycle 部分。

Frame Lifecycle section with different tracks

Frame Lifecycle 部分包含层名称和四个轨迹。每个轨迹代表帧渲染管道中的一个阶段。Frame Lifecycle 元素如下:

  1. Frame Lifecycle (Layer name):部分标题在括号中包含层名称。是合成的单个单元。
  2. Application:此轨迹显示从应用取出缓冲区到重新将缓冲区排入队列的时间。这通常对应于 RenderThread 中的轨迹事件。
  3. Wait for GPU:此轨迹显示缓冲区由 GPU 拥有的时间。这是从缓冲区发送到 GPU 到 GPU 完成其在缓冲区上的工作的时间。这并不表示 GPU 在此期间仅在此缓冲区上工作。有关 GPU 在给定时间内工作的详细信息,您可能需要使用 Android GPU Inspector
  4. Composition:此轨迹显示从 SurfaceFlinger 锁存缓冲区并发送进行合成,到缓冲区发送到显示器的时间。
  5. Frames on display:此轨迹显示帧在屏幕上显示的时间。

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

Android Studio 还在 All Frames 标签页中以表格形式显示轨迹中的所有帧。

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

Frame #ApplicationWait for GPUComposition 列表示与上述 Frame Lifecycle 部分中的轨迹相同的数据。Frame Duration 列表示从 Application 开始到 Frames on Display 开始的时间。这本质上是渲染一帧端到端所需的时间。

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

要在 Android 11 上检测和调查卡顿,请按照以下步骤操作:

  1. Application 列降序排序 All Frames 表,以便最长的帧首先显示。

    Application column sorted in descending order

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

    Timeline view alongside Frames table

  3. Frame LifecycleThreads 部分中查找相关线程。

    Frame Lifecycle and Threads sections

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

对于使用 Android 10(API 级别 29)及更低版本的设备,相关的 OS 图形管道信息显示在 CPU Profiler 系统轨迹的一个名为 Display 的部分中。

The display UI window

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

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

The Threads section under Display

上图中的 Threads 部分显示了 UI 线程 (java.com.google.samples.apps.iosched)、RenderThreadGPU completion 线程。这些是与 UI 渲染相关的线程,可能会导致卡顿。

要在 Android 10 或更低版本上检测卡顿,请按照以下步骤操作:

  1. 查看 Display 中的 Frames 轨迹。红色帧是需要调查的候选帧。

    The Frames section under Display

  2. 找到一个潜在的卡顿帧后,按 W 或在按住 Control(macOS 上为 Command)的同时滚动鼠标滚轮来放大。继续放大,直到您开始看到 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

了解更多

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