60fps — 是每秒60帧的频率,每帧恰好占用16.7毫秒,提供视觉上流畅的运动。根据Android Game Optimization Guide,稳定的60 FPS被认为是移动应用中舒适动画的最低标准。16.7 ms — 是渲染一帧的时间预算,开发者必须遵守才能达到60 FPS。
要点
60fps(每秒60帧,frames per second)— 帧变化频率指标,显示器每秒刷新图像60次。由于视觉暂留效应,人眼在大约50–60Hz时就不再区分离散的帧,这使得60fps成为大多数用户自然的流畅度阈值。
在60fps下,每帧有固定的时间预算16.67毫秒。这个预算包括所有时间:从处理用户输入到渲染和输出到屏幕。如果任何操作 — 物理、动画、复杂场景的绘制 — 超过这个限制,帧率就会下降到30fps或更低,在视觉上会被感知为卡顿。
在移动开发中,由于硬件限制,60fps长期以来一直是上限:大多数显示器在2017年之前运行在60Hz。随着90Hz和120Hz屏幕的出现,60fps成为了下限标准,而不是上限目标。但对于UI应用程序、视频和大多数休闲游戏来说,60fps仍然是性能的目标指标。
60Hz — 美国和日本电网中交流电的频率,历史上决定了最早NTSC电视标准的扫描频率。PAL标准由于欧洲电网为50Hz而使用了50Hz。这种历史惯性转移到了计算机显示器,随后又转移到了移动显示器上。
暂留效应 — 人类视觉在刺激消失后约30–50毫秒内将图像保留在视网膜上的特性。在60fps下,新帧每16.7毫秒到达一次 — 早于前一帧的暂留痕迹消失,从而创造出连续运动的错觉。卡迪夫大学(2023)的研究表明,战斗机飞行员能够在220Hz下分辨出单个帧,但对于普通用户来说,60Hz和120Hz之间的差异远不如30Hz和60Hz之间的差异明显。
Apple在2007年随第一款iPhone将60fps设定为iOS的标准,并一直保持到iPhone 13 Pro(2021)。Android历史上遵循了相同的标准,尽管第一款90Hz(OnePlus 7 Pro,2019)和120Hz(Razer Phone,2017)的设备更早出现。如今,60fps是带有动画的应用程序通过App Store和Google Play审核的最低门槛,尽管这些要求并未正式记录在案。
测量FPS — 优化的第一步。没有客观指标就无法确定性能究竟损失在哪里。移动平台提供了内置的性能分析工具和软件API来实时测量帧率。
Android Studio Profiler和Xcode Instruments — 分析FPS的主要工具。Android Profiler显示GPU渲染时间、帧率和Jank(丢帧数量)。Xcode Instruments包含Core Animation模板,显示帧率、渲染时间和draw calls数量。对于游戏引擎,Unity Profiler和Unreal Insights提供了按模块划分的详细时间分解。
// Android — 通过FrameMetrics测量FPS
window.addOnFrameMetricsAvailableListener(
{ _, frameMetrics ->
val duration = frameMetrics[FrameMetrics.TOTAL_DURATION]
val fps = 1000f / (duration / 1_000_000f)
Log.d("FPS", "Frame duration: ${duration / 1_000_000} ms, FPS: $fps")
},
Handler(Looper.getMainLooper())
)
CADisplayLink在iOS和Choreographer在Android中 — 将渲染与显示器刷新率同步的系统机制。CADisplayLink在每个新帧时调用方法,传递时间戳以计算延迟。Android中的Choreographer执行相同操作,但支持帧的不同阶段的回调:输入、动画、treviz、渲染。开发者可以订阅Choreographer.FrameCallback并测量帧之间的时间。
稳定的60fps意味着没有帧超过16.7毫秒的预算。即使每秒只有一个长帧也会造成明显的卡顿。优化分为三个层级:CPU、GPU和内存。每个层级都可能成为瓶颈。
布局传递 — Android和iOS上CPU时间的主要消耗者之一。复杂的视图层级、嵌套的ConstraintLayout、繁重的drawable会创建漫长的measure和layout链。对于UI应用程序,使用扁平化的视图层级(深度不超过3–4层),将嵌套的RecyclerView替换为ConcatAdapter,在iOS中为列表使用带有预获取的compositional layout。
| 操作 | 典型时间 | 超限时的影帽 |
|---|---|---|
| 布局 | 1–3 ms | 复杂屏幕上的卡顿 |
| 绘制 | 2–8 ms | 重绘、丢帧 |
| GPU渲染 | 3–10 ms | FPS下降一半 |
| GC(垃圾回收) | 2–50 ms | 可见的微卡顿 |
过度绘制 — 多次渲染相同的像素。每一层View、背景、透明元素下的图像都增加了像素操作的数量。在Android中,使用开发者选项中的Debug GPU Overdraw,在iOS中 — Xcode Debug View Hierarchy。通过移除不必要的背景和使用opaque标志来减少过度绘制:在Android中 — 使用带android:opaque的@drawable,在iOS中 — UIKit.View的isOpaque = true。
绘制调用 — 发送到GPU的渲染命令数量。现代移动GPU在60fps下每帧处理200–400个draw calls。超过这个数字会导致性能下降。将精灵合并到纹理图集中,使用批处理,避免通过单独的draw call单独渲染每个元素。
GC暂停 — JVM和Kotlin应用程序中FPS不稳定的主要原因之一。Android上的垃圾回收可能耗时30–50毫秒,导致连续2–3帧被跳过。避免在动画循环中进行分配,使用对象池和预先分配内存。在iOS上,由于ARC的存在,问题不那么严重,但保留循环和自动释放池溢出也会造成微暂停。
对于游戏来说,60fps不仅仅是标准,更是竞争优势。Newzoo(2024)的研究表明,FPS不稳定的低于60的游戏在Google Play中收到的负面评论多40%。Unity和Unreal Engine提供了内置的性能分析器来控制渲染时间:在Unity中是Frame Debugger,在Unreal中是GPU Visualizer,它们显示每个draw call和shader的精确时间。稳定的60fps对于动作游戏尤其重要,每个丢帧都可能导致用户失去通关机会。
90Hz和120Hz显示器改变了性能目标。对于在ProMotion设备上运行的应用程序,目标FPS可以是120,帧预算减少到8.3毫秒。这需要两倍效率的代码,特别是在draw calls和GPU渲染方面。
高频率的优势不仅仅在于流畅度:120fps将可感知的输入延迟减少了8–10毫秒,这对游戏和交互式应用程序至关重要。然而,60和120fps之间的差异需要个别化方法:对于UI应用程序(滚动、动画),90fps可能是流畅度和能耗之间的最佳折衷,因为每秒渲染120帧比60帧消耗30–40%更多的能量。
Apple提供了选择首选频率的API:CADisplayLink中的preferredFramesPerSecond。Android在API 30之前不提供对频率的直接控制,但从Android 12开始,开发者可以通过WindowManager设置RefreshRate,根据内容类型请求60、90或120Hz。
常见问题
30fps在滚动和动画时会被感知为抖动,因为每帧持续33.3毫秒,眼睛能够察觉到不连续性。60fps每16.7毫秒提供一帧 — 低于大多数用户的视觉暂留阈值。
使用性能分析器(Android Profiler、Xcode Instruments)并查看帧时间直方图。如果90%以上的帧在16.7毫秒内没有尖峰 — FPS是稳定的。单个尖峰达到30–50毫秒会造成明显的卡顿。
可以,但这需要激进的优化:低渲染分辨率、简单的着色器、最少的draw calls数量、放弃透明度和复杂阴影。在低端设备上测试 — 它们会显示真实的性能。
由于VSync机制:如果GPU无法在16.7毫秒内完成帧,它会错过VBlank并将当前帧再保持16.7毫秒。实际上一个帧显示两个刷新周期,FPS正好下降一半。
是的。即使是简单的列表滚动和过渡动画也需要60fps才能舒适地感知。用户立即注意到滑动时的减速,这会在主观测试中将应用程序的评分降低2–3倍。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。