Android 通过生成应用帧并在屏幕上显示来渲染 UI。如果您的应用 UI 渲染缓慢,则系统将被迫跳过帧。发生这种情况时,用户会在屏幕上感知到反复的闪烁,这被称为卡顿。
当发生卡顿时,通常是由于 UI 线程(在大多数应用中是主线程)上存在某种减速或阻塞的异步调用。您可以使用系统轨迹来识别问题所在。
在 Android 12 及更高版本上检测卡顿
对于使用 Android 12(API 级别 31)或更高版本的设备,捕获的轨迹会显示在 CPU Profiler 的 Display 窗格下方的 Janky frames 轨迹中。
要检测卡顿,请执行以下操作:
在 Android Studio 中,选择 View > Tool Windows > Profiler 或点击工具栏中的 Profile
。如果出现 Select Deployment Target 对话框,请选择要用于分析的应用部署设备。如果您已通过 USB 连接设备但未看到它列出,请确保您已启用 USB 调试。
点击 CPU 时间轴中的任意位置以打开 CPU Profiler。
从 CPU Profiler 中的配置菜单中选择 System Trace,然后点击 Record。与应用交互完成后,点击 Stop。
您应该会在 Display 下看到 Janky frames 轨迹。默认情况下,Profiler 只会将卡顿帧显示为调查对象。在每个卡顿帧内,红色部分会突出显示帧超出其渲染截止时间的持续时间。

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

您可以通过分别勾选 All Frames 和 Lifecycle 复选框来选择查看所有帧或渲染时间的细分。

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

Frame Lifecycle 部分包含层名称和四个轨迹。每个轨迹代表帧渲染管道中的一个阶段。Frame Lifecycle 元素如下:
- Frame Lifecycle (Layer name):部分标题在括号中包含层名称。层是合成的单个单元。
- Application:此轨迹显示从应用取出缓冲区到重新将缓冲区排入队列的时间。这通常对应于
RenderThread中的轨迹事件。 - Wait for GPU:此轨迹显示缓冲区由 GPU 拥有的时间。这是从缓冲区发送到 GPU 到 GPU 完成其在缓冲区上的工作的时间。这并不表示 GPU 在此期间仅在此缓冲区上工作。有关 GPU 在给定时间内工作的详细信息,您可能需要使用 Android GPU Inspector。
- Composition:此轨迹显示从 SurfaceFlinger 锁存缓冲区并发送进行合成,到缓冲区发送到显示器的时间。
- Frames on display:此轨迹显示帧在屏幕上显示的时间。
Frame Lifecycle 部分说明了帧缓冲区如何在渲染管道的不同阶段之间移动。帧按帧号进行颜色编码,以便更轻松地跟踪特定帧。
Android Studio 还在 All Frames 标签页中以表格形式显示轨迹中的所有帧。

Frame #、Application、Wait for GPU 和 Composition 列表示与上述 Frame Lifecycle 部分中的轨迹相同的数据。Frame Duration 列表示从 Application 开始到 Frames on Display 开始的时间。这本质上是渲染一帧端到端所需的时间。
您可以按任意列对帧表进行排序,以快速找到最短或最长的帧。该表还支持分页控件,帮助您浏览数百个帧。
要在 Android 11 上检测和调查卡顿,请按照以下步骤操作:
按 Application 列降序排序 All Frames 表,以便最长的帧首先显示。

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

在 Frame Lifecycle 和 Threads 部分中查找相关线程。

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

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

上图中的 Threads 部分显示了 UI 线程 (java.com.google.samples.apps.iosched)、RenderThread 和 GPU completion 线程。这些是与 UI 渲染相关的线程,可能会导致卡顿。
要在 Android 10 或更低版本上检测卡顿,请按照以下步骤操作:
查看 Display 中的 Frames 轨迹。红色帧是需要调查的候选帧。

找到一个潜在的卡顿帧后,按
W或在按住 Control(macOS 上为 Command)的同时滚动鼠标滚轮来放大。继续放大,直到您开始看到 UI 线程和RenderThread中的轨迹事件。
在上图中,
Choreographer#doFrame显示 UI 线程何时调用Choreographer来协调动画、视图布局、图像绘制和相关进程。DrawFrames显示RenderThread何时形成并向 GPU 发出实际绘制命令。如果您看到特别长的轨迹事件,您可以进一步放大并找出可能导致渲染缓慢的原因。上图显示了 UI 线程中的
inflate,这意味着应用正在花费时间来膨胀布局。当您放大其中一个inflate事件时,您可以精确地找出每个 UI 组件花费了多长时间,如下所示。
了解更多
要了解有关如何减少卡顿的更多信息,请参阅常见卡顿来源。