当在 Android 中启动动画时,显示屏通常会提升到最大刷新率,以确保流畅的体验。对于进度条和音频可视化工具等小型动画,这种高刷新率是不必要的,并且会导致高功耗。
从 Android 15 开始,借助自适应刷新率 (ARR) 功能,已启用该功能的设备可以从以下两个方面减少高刷新率驻留时间:
- 借助新的平台帧速率管理优化,应用可以默认以较低的帧速率进行渲染,仅在必要时提升到高帧速率。
- 显示屏刷新率可动态匹配内容渲染速率,而不会出现卡顿。
虽然大多数应用都应能从 ARR 中受益,而无需进行任何修改,但您也可以根据需要替换默认帧速率行为。
本页介绍以下内容:
- 每个视图的帧速率是如何确定的。
- ARR 确定帧速率设置方式的一般政策。
- 如何手动替换默认帧速率行为。
The View 投票机制
在 Android 的 View 系统中,界面层次结构中的每个 View 都可以表达其首选帧速率。系统会收集并合并这些偏好设置,以确定每个帧的最终帧速率。这是通过一种投票机制实现的,其中每个视图都根据其帧速率属性(可以是类别或特定速率)进行投票。视图通常在绘制或更新时进行投票。这些投票结果会合并,以确定最终的帧速率,然后作为渲染提示发送到较低级别的层。
目前,大多数视图默认采用“正常”帧速率,通常设置为 60 Hz。如需更高的帧速率,您可以使用特定 API 自定义偏好设置,系统通常会选择最高的帧速率。如需详细了解如何使用这些 API,请参阅设置帧速率或类别部分。一般 ARR 政策部分介绍了与帧速率相关的一般政策。
帧速率类别
在 View
类中,有不同的帧速率类别可用于投票。各类别的说明如下:
REQUESTED_FRAME_RATE_CATEGORY_DEFAULT
:您可以将此值设置为恢复默认行为,表示相应视图没有帧速率数据。REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE
:视图将明确不影响帧速率。这意味着,即使视图处于活跃状态,框架在确定帧速率时也不会考虑该视图REQUESTED_FRAME_RATE_CATEGORY_NORMAL
:表示适合不需要更高帧速率或无法从高平滑度中获益的动画的中等帧速率。通常为 60 Hz 或接近 60 Hz。REQUESTED_FRAME_RATE_CATEGORY_HIGH
:表示适合需要高帧速率的动画的帧速率,这可能会提高流畅度,但也可能会增加耗电量。
仅当 View 需要重绘时,才会进行投票。最终帧速率由得票最高的帧速率决定。例如,如果所有投票都投给了“正常”,则选择“正常”。如果同时出现“普通”和“高”投票,则选择“高”。
帧速率
除了帧速率类别之外,视图还可以指定首选帧速率,例如 30、60 或 120 Hz。当投出多个帧速率票时,最终帧速率将根据以下规则确定:
- 互为倍数:如果投票的帧速率互为倍数,则选择最高值。例如,如果有两个投票结果(30 Hz 和 90 Hz),则选择 90 Hz 作为最终帧速率。
- 不是彼此的倍数:
- 如果任何投票结果大于 60 Hz,则计为“高”投票。
- 如果所有投票结果均为 60 Hz 或更低,则视为“正常”投票。
此外,如果同时存在帧速率值和帧速率类别,则通常较高的值决定最终的渲染速率。例如,如果同时投了 60 Hz 和“高”票,或者同时投了 120 Hz 和“正常”票,渲染速率通常会设置为 120 Hz。
除了来自应用的投票之外,同一帧内不同组件也可能会向较低层发送其他提示。其中许多事件可能源自系统界面组件,例如通知栏、状态栏、导航栏等。最终帧速率值根据多个组件的投票结果确定。
设置帧速率或类别
在某些情况下,您可能希望为某个视图设置首选帧速率。例如,您可以将某个视图的首选帧速率设置为“高”,以便在动画显示不流畅时提高帧速率。此外,如果视频中包含缓慢或静态动画(通常以 24 或 30 Hz 的速率播放),您可能希望以低于“正常”的速率运行动画,以降低能耗。
您可以使用 setRequestedFrameRate()
和 getRequestedFrameRate()
API 来指定给定 View 的首选帧速率或类别。
Kotlin
// Set the preferred frame rate category to a View // set the frame rate category to NORMAL view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL // set the frame rate category to HIGH view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_HIGH // reset the frame rate category view.requestedFrameRate = View.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT // Set the preferred frame rate to a View // set the frame rate to 30 view.requestedFrameRate = 30f // set the frame rate to 60 view.requestedFrameRate = 60f // set the frame rate to 120 view.requestedFrameRate = 120f
Java
// Set the preferred frame rate category to a View // set the frame rate category to NORMAL view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_NORMAL); // set the frame rate category to HIGH view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_HIGH); // reset the frame rate category view.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); // Set the preferred frame rate to a View // set the frame rate to 30 view.setRequestedFrameRate(30); // set the frame rate to 60 view.setRequestedFrameRate(60); // set the frame rate to 120 view.setRequestedFrameRate(120);
如需查看使用示例,请参阅 TextureView
。
一般 ARR 政策
在上一部分中,我们讨论了大多数动画默认以 60 Hz 的频率显示,因为每个视图都将“正常”设置为首选帧速率。不过,在某些情况下,帧速率会增加到“高”,以确保动画更流畅。
一般 ARR 政策如下:
- 触控加速:检测到触控事件 (
MotionEvent.ACTION_DOWN
) 时,在松开触控后的一段时间内,刷新率会提升到“高”,以保持响应速度。 - 轻拂手势:轻拂手势的处理方式有所不同,刷新率会随着轻拂速度的减慢而逐渐降低。您可以在滚动改进部分中找到有关此行为的详细信息。
- 应用启动和窗口过渡:在应用启动、窗口初始化和窗口过渡期间,刷新率也会在一段时间内得到提升,以确保流畅的视觉体验。
- 动画:涉及移动或大小变化的动画会自动获得更高的刷新率,以便在视图的位置或大小发生变化时提高流畅度。
SurfaceView
和TextureView
:系统会遵循并相应应用为TextureView
和SurfaceView
明确设置的帧速率。
启用和停用触控增强功能
您可以在 Window
级别启用和/或停用触控增强功能。默认情况下,当用户触摸屏幕并将手指从屏幕上移开时,渲染速率会在一段时间内提高。借助 setFrameRateBoostOnTouchEnabled()
和 getFrameRateBoostOnTouchEnabled()
API,您可以在触摸特定 Window
时防止渲染速率增加。
Kotlin
// disable touch boost on a Window window.isFrameRateBoostOnTouchEnabled = false // enable touch boost on a Window window.isFrameRateBoostOnTouchEnabled = true // check if touch boost is enabled on a Window val isTouchBoostEnabled = window.isFrameRateBoostOnTouchEnabled
Java
// disable touch boost on a Window window.setFrameRateBoostOnTouchEnabled(false) // enable touch boost on a Window window.setFrameRateBoostOnTouchEnabled(true) // check if touch boost is enabled on a Window window.getFrameRateBoostOnTouchEnabled()
滚动改进
动态优化帧速率的一个关键使用场景是改善滚动(轻拂)体验。许多应用都非常依赖用户向上滑动来查看新内容。ARR 滚动增强功能可在快速滑动减速时动态调整刷新率,逐渐降低帧速率。这样一来,在保持流畅滚动的同时,渲染效率也会更高。
此改进专门适用于可滚动的界面组件,包括 ScrollView
、ListView
和 GridView
,可能不适用于所有自定义实现。
ARR 滚动功能适用于 RecyclerView
和 NestedScrollView
。如需在应用中启用此功能,请升级到 AndroidX.recyclerview
和 AndroidX.core
的最新版本。有关详情,请参阅下表。
库 |
版本 |
|
1.4.0 |
|
1.15.0 |
设置速度信息
如果您有自定义的可滚动组件,并且想利用滚动功能,请在流畅滚动或快速滑动时,在每个帧上调用 setFrameContentVelocity()
。如需查看示例,请参阅以下代码段:
Kotlin
// set the velocity to a View (1000 pixels/Second) view.frameContentVelocity = 1000f // get the velocity of a View val velocity = view.frameContentVelocity
Java
// set the velocity to a View view.setFrameContentVelocity(velocity); // get the velocity of a View final float velocity = view.getFrameContentVelocity()
如需查看更多示例,请参阅 RecyclerView
和 ScrollView
。如需正确设置速度,如果无法从 Scroller
或 OverScroller
获取所需信息,请手动计算内容速度(像素/秒)。
请注意,如果对不可滚动的组件调用 setFrameContentVelocity()
和 getFrameContentVelocity()
,则它们不会产生任何效果,因为移动会自动根据当前政策触发更高的帧速率。
速度信息对于调整渲染速率至关重要。例如,考虑轻拂手势。在开始时,轻拂的速度可能很高,因此需要更高的渲染速率才能确保流畅性。随着手势的进行,速度会降低,从而可以降低渲染速率。
启用和停用 ARR
ARR 默认处于启用状态,以提高能效。虽然您可以停用此功能,但不建议这样做,因为这样会导致应用消耗更多电量。只有在遇到严重影响用户体验的问题时,才考虑停用此功能。
如需启用或停用 ARR,请在 Window
上使用 setFrameRatePowerSavingsBalanced()
API,或通过 styles.xml
文件使用 isFrameRatePowerSavingsBalanced()
API。
以下代码段展示了如何在 Window
上启用或停用 ARR:
Kotlin
// disable ARR on a Window window.isFrameRatePowerSavingsBalanced = false // enable ARR on a Window window.isFrameRatePowerSavingsBalanced = true // check if ARR is enabled on a Window val isAdaptiveRefreshRateEnabled = window.isFrameRatePowerSavingsBalanced
Java
// disable ARR on a Window window.setFrameRatePowerSavingsBalanced(false) // enable ARR on a Window window.setFrameRatePowerSavingsBalanced(true) // check if ARR is enabled on a Window window.isFrameRatePowerSavingsBalanced()
如需通过 styles.xml
文件停用 ARR,请将以下项添加到 res/values/styles.xml
中的样式中:
<style name="frameRatePowerSavingsBalancedDisabled">
<item name="android:windowIsFrameRatePowerSavingsBalanced">false</item>
</style>
Compose 的 ARR
Compose 1.9 还增加了对自适应刷新率的支持。
在 View 系统中,您可以使用 setRequestedFrameRate()
方法为 View 请求特定的帧速率。在 Compose 中,借助新的修饰符,您可以为可组合项指定帧速率。此修饰符的功能与 setRequestedFrameRate()
类似,可接受正帧速率值(以 Hz 为单位)或预定义的帧速率类别 FrameRateCategory
。
相应 API 的签名如下所示:
Modifier.preferredFrameRate(frameRate: Float)
Modifier.preferredFrameRate(frameRateCategory: FrameRateCategory)
在下面的代码段中,新的帧速率修饰符 (Modifier.requestedFrameRate(120f))
应用于 Text
可组合项。此修饰符会导致 Text
可组合项在绘制或添加动画效果(例如,更改不透明度)时请求首选帧速率为 120:
var targetAlpha by remember { mutableFloatStateOf(1f) }
val alpha by
animateFloatAsState(
targetValue = targetAlpha,
animationSpec = tween(durationMillis = 1000)
)
Button(
onClick = { targetAlpha = if (targetAlpha == 1f) 0.2f else 1f },
modifier =
Modifier.background(LocalContentColor.current.copy(alpha = alpha))
) {
Text(
text = "Click",
color = LocalContentColor.current.copy(alpha = alpha),
modifier = Modifier.preferredFrameRate(120f)
// You can also pass frame rate category such as FrameRateCategory.High to increase the frame rate
)
}
然后,系统会收集并整合所有可组合项的首选帧速率,以确定每个帧的最终帧速率。如需了解详情,请参阅 SetFrameRateSample
和 SetFrameRateCategorySample
。