移动应用中的帧率 — 是什么、fps以及如何提高

作者: IT Sectr 发布日期: 2026-03-31 阅读时间: 10 分钟

Frame Rate — 是图形系统在一秒内显示的帧数。在移动应用中,帧频直接决定动画、滚动和屏幕切换的流畅度。根据 Android Developers, 2025 的数据,目标 Frame Rate 对于标准显示屏为60 fps,对于高刷新率设备为120 fps。偏离目标值会导致视觉卡顿和用户体验下降。

要点

  • Frame Rate — 每秒帧数(fps),决定UI的流畅度。
  • 标准目标Frame Rate — 60 fps,对应每帧16.6毫秒。
  • 配备 120 Hz 显示屏的设备需要120 fps(每帧8.3毫秒)。
  • 丢帧会导致 Jank — 明显的动画卡顿。
  • Frame Rate分析 — 优化UI性能的第一步。

什么是Frame Rate

Frame Rate(帧率)— 是一种以每秒帧数(fps)为单位的度量,表示应用每秒更新屏幕图像的次数。人眼从24 fps(电影)开始将运动感知为流畅,但对于交互式UI,至少需要60 fps才能使触摸和动画感觉即时。每一帧都是一个完整的周期:处理用户输入、计算布局、渲染视图层次和输出到屏幕。如果任何阶段超过了分配的时间预算(60 fps时为16.6毫秒),帧将被丢弃,用户会看到卡顿。

区分应用的 Frame Rate 与显示屏的刷新率(Refresh Rate)很重要。刷新率是屏幕的特性:显示屏每秒物理刷新图像的次数(60、90、120或144 Hz)。Frame Rate — 是应用每秒能够渲染的帧数。如果应用在120 Hz显示屏上输出60 fps,每第二帧将被重复 — 图像保持流畅,但不如应有的响应灵敏。根据Google I/O 2023的数据,现代旗舰机可以在简单的UI场景中保持120 fps,但在重负载下(游戏、复杂列表)频率下降到40–60 fps。

帧渲染如何工作

移动应用中的帧渲染经过多个阶段的管道。在Android中,管道包括:输入处理(Input)、动画(Animation)、测量和布局(Layout)、绘制(Draw)、与GPU同步和输出到屏幕(Swap)。每个阶段在CPU或GPU上执行,所有阶段的总时间不得超过帧预算。对于60 fps,预算为16.6毫秒,对于120 fps — 8.3毫秒。Choreographer(Android)和 CADisplayLink(iOS)将渲染与显示屏的垂直刷新(VSync)同步,确保帧仅在屏幕刷新时显示,避免图像撕裂(tearing)。

在iOS中,管道类似:Run Loop 处理事件,Core Animation计算图层,Render Server(独立进程)渲染并将帧发送到GPU。iOS的区别在于独立的Render Server进程,它将渲染与主应用隔离。如果应用阻塞主线程,Render Server仍然可以显示最后一个已知帧,但动画将停止。如果Render Server本身跟不上 — GPU空闲,Frame Rate下降。根据Apple WWDC 2022的数据,iOS中Frame Rate低的最常见原因是CALayer过度嵌套、繁重的shadowPath和离屏渲染(offscreen rendering)。

通过Choreographer跟踪帧

Kotlin代码订阅 Choreographer.FrameCallback 并记录帧之间的实际时间。如果间隔超过16.6毫秒 — 记录丢帧。

kotlin
class FrameRateMonitor {

    private var lastFrameTime = 0L
    private val frameCallback =
        Choreographer.FrameCallback { frameTimeNanos ->
            if (lastFrameTime != 0L) {
                val deltaMs = (frameTimeNanos - lastFrameTime) / 1_000_000f
                if (deltaMs > 16.6f) {
                    Log.w("FrameRate",
                        "Skipped frame: $deltaMs ms")
                }
            }
            lastFrameTime = frameTimeNanos
            Choreographer.getInstance()
                .postFrameCallback(this)
        }

    fun start() {
        Choreographer.getInstance()
            .postFrameCallback(frameCallback)
    }
}

显示屏刷新率和Frame Rate

Refresh Rate(刷新率)— 是显示屏的硬件特性,决定屏幕每秒物理重绘图像的次数。标准显示屏为60 Hz,现代旗舰机 — 90、120或144 Hz。应用的 Frame Rate 可以低于、等于或高于刷新率(在后一种情况下,多余的帧被丢弃)。理想情况 — Frame Rate与Refresh Rate一致:每个硬件周期从应用获得新帧,运动最流畅。如果Frame Rate较低,显示屏重复最后一帧,这会被感知为微卡顿(stutter)。

Android和iOS支持动态切换刷新率。Android 12+使用 Smart Refresh Rate:滚动时系统将频率提高到120 Hz,静态内容时降低到60 Hz以节省电池。iOS ProMotion(iPhone 13 Pro及更新机型)类似工作 — 频率根据内容在10到120 Hz之间变化。开发者应检查设备是否支持高频率,并调整每帧的时间预算。如果应用无法在8.3毫秒内(对于120 Hz)渲染帧,最好强制以60 Hz工作 — 这将确保稳定的Frame Rate而不会丢帧。

显示屏类型Refresh Rate每帧预算设备
标准60 Hz16.6毫秒大多数Android/iOS
90 Hz11.1毫秒OnePlus, Pixel 6+
旗舰120 Hz8.3毫秒iPhone Pro, Galaxy S22+
游戏144 Hz6.9毫秒ROG Phone, Nubia RedMagic

Frame Rate测量工具

在移动应用中测量 Frame Rate,既有平台内置工具,也有第三方分析器可用。在Android中,主要工具是 GPU Profiling(Developer Options → Profile GPU Rendering),它按阶段(Draw, Prepare, Process, Execute)显示每个帧的时间线。更详细的分析由 Android Studio Profiler 提供 — 它记录完整的渲染配置文件,指出导致重绘的特定View。在iOS中,使用 InstrumentsCore Animation 模板 — 显示FPS、图层渲染时间和离屏渲染次数。

用于生产环境的Frame Rate监控使用 Firebase Performance(Android)— 它在后台收集 Frame Rate,并按设备、操作系统版本和会话进行聚合。在iOS中,MetricKit 通过 MXAnimatoryMetric 提供类似数据。对于游戏和Flutter应用,使用 FrameTimingCallback(Flutter)和 Unity Profiler。重要的是测量不是平均Frame Rate,而是百分位数:P50、P90和P99。应用可能显示平均55 fps,但P99 = 30 fps — 这意味着1%的时间用户看到严重卡顿,这足以导致负面评价。

在Flutter中测量Frame Rate

Dart示例展示了如何在Flutter中订阅 FrameTimingCallback 并记录丢帧数。回调在每个完成的帧之后触发。

dart
import 'package:flutter/scheduler.dart';

class FrameRateLogger {
    int totalFrames = 0;
    int missedFrames = 0;

    void start() {
        SchedulerBinding.instance
            .addTimingsCallback(_onReportTimings);
    }

    void _onReportTimings(List<FrameTiming> timings) {
        for (final timing in timings) {
            totalFrames++;
            if (timing.totalSpan()
                > Duration(milliseconds: 16)) {
                missedFrames++;
            }
        }
        debugPrint("FPS: \${totalFrames - missedFrames}");
    }
}

优化帧频

优化 Frame Rate 从识别渲染管道中的瓶颈开始。在布局阶段,主要问题是视图层次过度嵌套、使用相对布局(具有大量规则的RelativeLayout)和频繁调用requestLayout。解决方案 — 使用ConstraintLayout或扁平层次,避免超过5–6层嵌套。在绘制阶段 — 过度绘制(overdraw):当像素每帧被绘制多次时。例如,半透明片段下的Activity白色背景,其下还有一层 — 每个像素被绘制三次。Debug GPU Overdraw 工具通过颜色指示显示问题区域。建议将overdraw保持在2x或更低水平。

在iOS中,主要问题是繁重的 cornerRadiusmasksToBounds — 它们导致离屏渲染(offscreen rendering),Core Animation创建临时缓冲区,在其中绘制,然后将结果复制到屏幕。离屏渲染在Instruments Core Animation中很容易发现:如果 Renderer 行为红色 — 存在问题。解决方案 — 使用带有预裁剪图像的 UIImageView 代替cornerRadius,避免在没有必要时使用 groupOpacityshouldRasterize。对于两个平台,最小化 invalidate()setNeedsDisplay() 的调用次数至关重要 — 每次这样的调用都会启动完整的视图重绘周期。

在Android中优化层次

代码演示了将RelativeLayout的深层嵌套替换为 ConstraintLayout 的扁平结构。将嵌套级别从4减少到1可使布局时间缩短30–50%。

kotlin
// 示例:通过ConstraintLayout的扁平结构
class OptimizedView(context: Context) :
    ConstraintLayout(context) {

    private val binding =
        ItemProfileBinding.inflate(
            LayoutInflater.from(context)
        )

    fun bind(user: User) {
        binding.avatar.setImageURI(user.avatarUrl)
        binding.nameText.text = user.name
        // 绑定数据而无需重绘整个容器
    }
}

自适应帧率和动态帧率

现代移动应用越来越多地使用自适应 Frame Rate — 一种根据当前场景动态调整目标帧率的系统。快速滚动时列表需要120 fps保证流畅性,在静态屏幕上60 fps甚至30 fps用于视频就足够了。在Android中,自适应通过 Choreographer.setFrameInterval(API 33+)和 Window.setFrameRate 实现。开发者可以向系统指示首选帧率:在SurfaceView中 setPreferredRefreshRate 或在Window中 setFrameRate。iOS通过 ProMotion 自动管理帧率,但开发者可以显式设置CADisplayLink的 preferredFramesPerSecond

动态帧率对于游戏和具有动画的应用尤其重要。根据Google数据,在静态屏幕上将Frame Rate从120 Hz降低到60 Hz可节省30–40%的GPU能耗。为了在流畅性和功耗之间实现最佳平衡,建议:在不同场景中测量实际Frame Rate,根据场景设置目标fps(游戏 — 60,菜单 — 30,视频 — 24),并通过生命周期感知组件切换模式,以便应用在最小化时不会在后台浪费资源渲染120 fps。

设置首选Frame Rate

Swift代码为iOS中CADisplayLink设置 preferredFramesPerSecond。滚动时频率升至120 Hz,停止时 — 降至60 Hz。

swift
class AdaptiveFrameRateManager {

    private var displayLink: CADisplayLink?

    func startWithHighRate() {
        displayLink = CADisplayLink(
            target: self,
            selector: #selector(step)
        )
        if #available(iOS 15.0, *) {
            displayLink?.preferredFrameRateRange =
                CAFrameRateRange(
                    minimum: 60,
                    maximum: 120,
                    preferred: 120
                )
        }
        displayLink?.add(to: .current,
            forMode: .common)
    }

    @objc
    private func step() {
        // 动画更新
    }
}

常见问题

对于移动应用,什么样的Frame Rate被认为是好的?

对于移动应用,目标 Frame Rate 是60 fps(每帧16.6毫秒)。对于配备120 Hz显示屏的设备,建议120 fps。低于30 fps的值会明显降低用户体验。

Frame Rate与显示屏刷新率有何不同?

Frame Rate — 应用每秒渲染的帧数。Refresh Rate — 显示屏每秒物理刷新图像的次数。当Frame Rate低于Refresh Rate时,显示屏重复最后一帧。

如何在Android中测量Frame Rate?

使用 GPU Profiling(开发者选项)、Android Studio ProfilerFirebase Performance。用于程序化测量 — 计算帧间隔的 Choreographer.FrameCallback

什么是overdraw以及它如何影响Frame Rate?

Overdraw — 同一像素每帧被多次绘制。每个额外层增加绘制阶段的时间并降低Frame Rate。最佳overdraw为2x,临界 — 4x及以上。

动态帧率如何节省电池?

在静态内容下,Dynamic Frame Rate 将频率降至30–60 Hz,GPU负载降低30–40%。滚动时频率升至90–120 Hz以保证流畅性。

总结

  • Frame Rate — 每秒帧数,决定UI和动画的流畅度。
  • 目标Frame Rate — 标准显示屏 60 fps(16.6毫秒),高刷新率 120 fps(8.3毫秒)。
  • 丢帧导致 Jank — 影响用户体验的可见卡顿。
  • Frame Rate低的主要原因 — 视图过度嵌套、overdraw和离屏渲染。
  • Choreographer(Android)和 CADisplayLink(iOS)将渲染与VSync同步。
  • 自适应Frame Rate在流畅性和功耗之间取得平衡,GPU负载降低高达40%。
  • Frame Rate分析 — 优化移动应用性能的第一步。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读