Android系统开发(十五):从 60Hz 到 120Hz,多刷新率进化简史
引言
欢迎来到“帧率探索实验室”!今天,我们要聊聊 Android 11 中对多种刷新率设备的支持。你可能会问:“这和我写代码有什么关系?”别急,高刷新率不仅仅让屏幕更顺滑,还会直接影响用户体验。想象一下,当你的 app 在 120Hz 上流畅飞舞,而别人的 app 却“卡”在 60Hz,是不是就已经赢了?本文将带你深挖多刷新率支持背后的硬核技术,帮助你的 app 成为用户的心头好。不多说了,先刷个屏,再来深入了解 Hz 的奥秘!
一、背景
自从手机厂商开始推出高刷新率设备,用户对“流畅体验”的期待不断提升。然而,高刷新率不仅仅是硬件层面的事,系统与应用也需要配合优化。Android 11 正是在这一背景下增加了对多种刷新率的支持。这项技术的核心,是通过 HAL(Hardware Abstraction Layer)、平台代码和全新的 SDK/NDK API,将设备能力和应用需求完美结合。想象一下,从 60Hz 到 90Hz,再到 120Hz,你的 app 瞬间“飞”起来,而用户的惊叹声便是对你努力的最好回报!
二、原理
多刷新率支持的核心,是如何让设备和应用协同工作,以实现动态调整帧率。
- HAL API:定义了设备硬件的能力接口。Android 11 中新增的
android.hardware.graphics.composer@2.4
,负责管理设备支持的刷新率范围。 - 平台代码:系统解析设备配置文件,读取支持的刷新率选项,并为开发者提供设置接口。
- SDK 和 NDK API:通过 Java 或 C++ 调用,开发者可以指定应用的目标帧率。例如,游戏可以设置 120Hz,而视频播放可能限制在 60Hz。
这些组件协作,实现了设备硬件能力与应用实际需求的无缝对接。
三、实现
工具和环境
- Android Studio 4.0 或更高版本
- 支持多刷新率的 Android 11 设备
- 必备工具:ADB 调试工具
步骤详解
-
读取设备支持的刷新率
Display display = getDisplay(); Display.Mode[] modes = display.getSupportedModes(); for (Display.Mode mode : modes) {Log.d("RefreshRate", "Mode: " + mode.getRefreshRate() + " Hz"); }
-
设置目标帧率
使用Surface.setFrameRate()
API 设置帧率:Surface surface = getSurface(); surface.setFrameRate(120.0f, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT);
-
配置设备支持刷新率
在res/xml/device_config.xml
中定义设备支持的刷新率范围:<device><refresh-rate><min>60</min><max>120</max></refresh-rate> </device>
四、项目实战:高刷新率
在多刷新率支持的开发中,我们将通过三个实际案例展示如何实现动态刷新率设置。每个案例不仅包含详细实现步骤,还会提供代码示例,让你可以直接在项目中运行。
案例 1:高刷新率游戏开发
需求描述
为一款 FPS 游戏设置目标帧率为 120Hz,以提高用户的游戏体验,减少画面延迟感,确保高流畅度。
实现步骤
-
检查设备支持的刷新率
在游戏初始化时,读取设备支持的刷新率范围,确保目标帧率可以被支持。Display display = getWindowManager().getDefaultDisplay(); Display.Mode[] modes = display.getSupportedModes(); for (Display.Mode mode : modes) {Log.d("GameRefreshRate", "Supported Refresh Rate: " + mode.getRefreshRate() + " Hz"); }
-
设置高刷新率
在游戏的主要渲染窗口(SurfaceView
或SurfaceHolder
)中,调用Surface.setFrameRate()
,指定目标刷新率为 120Hz。Surface surface = surfaceView.getHolder().getSurface(); surface.setFrameRate(120.0f, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT);
-
优化渲染逻辑
使用Choreographer
实现高帧率下的精准帧同步。Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {@Overridepublic void doFrame(long frameTimeNanos) {renderFrame(); // 渲染游戏帧Choreographer.getInstance().postFrameCallback(this);} });
最终效果
运行在支持 120Hz 刷新率设备上的游戏画面更流畅,用户操作响应更加快速,显著提升了用户体验。
案例 2:高效视频播放器开发
需求描述
在一个视频播放器中,根据视频帧率动态调整设备的刷新率,以确保流畅播放,并避免额外的功耗。例如,为 30fps 视频设置 60Hz 刷新率,为 60fps 视频设置 120Hz 刷新率。
实现步骤
-
获取视频帧率
在播放器初始化时,解析视频文件,获取其原始帧率。MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(videoPath); MediaFormat format = extractor.getTrackFormat(0); int frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE); Log.d("VideoPlayer", "Video Frame Rate: " + frameRate);
-
动态调整刷新率
根据帧率,调用Surface.setFrameRate()
设置设备刷新率。float targetRefreshRate = frameRate > 60 ? 120.0f : 60.0f; surface.setFrameRate(targetRefreshRate, Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);
-
同步播放帧率
使用ExoPlayer
的帧回调功能,与设备刷新率同步。player.setVideoFrameMetadataListener((presentationTimeUs, releaseTimeNs, format) -> {surface.setFrameRate(format.frameRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT); });
最终效果
视频播放始终匹配设备刷新率,避免因刷新率差异导致的卡顿或撕裂现象,同时节省电量。
案例 3:动态刷新率切换应用
需求描述
开发一个动态切换刷新率的工具应用,用户可以通过界面选择不同的目标刷新率,并实时应用到设备屏幕。
实现步骤
-
设计 UI 界面
提供一个下拉菜单,显示设备支持的所有刷新率选项。<Spinnerandroid:id="@+id/spinner_refresh_rate"android:layout_width="wrap_content"android:layout_height="wrap_content"android:entries="@array/refresh_rates" />
-
获取支持的刷新率
在Activity
初始化时,读取设备支持的刷新率,并填充到下拉菜单中。Display display = getWindowManager().getDefaultDisplay(); Display.Mode[] modes = display.getSupportedModes(); ArrayList<String> refreshRates = new ArrayList<>(); for (Display.Mode mode : modes) {refreshRates.add(mode.getRefreshRate() + " Hz"); } ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, refreshRates); spinner.setAdapter(adapter);
-
实现动态切换逻辑
根据用户选择,动态应用刷新率。spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {Display.Mode mode = modes[position];Window window = getWindow();window.setPreferredRefreshRate(mode.getRefreshRate());}@Overridepublic void onNothingSelected(AdapterView<?> parent) {} });
-
适配不同设备
检查设备是否支持动态刷新率切换,确保应用在低版本设备上可以正常运行。if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {// 支持 Android 11 以上的设备动态刷新率切换 } else {Log.w("RefreshRateApp", "Dynamic refresh rate not supported on this device."); }
最终效果
用户可以通过界面实时切换刷新率,应用直接调整屏幕刷新率,感受到流畅与动态切换的便利。
归纳
这些项目展示了多刷新率支持的不同应用场景,包括高帧率游戏、流畅视频播放器和动态刷新率工具。每个案例都提供了详细的代码与实现步骤,可以直接用于实践或改进开发效率。
五、避坑
- 设备支持问题:并非所有设备都支持高刷新率,需检查兼容性。
- 耗电问题:高刷新率耗电量增加,需平衡性能与功耗。
- API 调用失败:确保使用了 Android 11 或更高版本的 API。
六、快稳省
优点
- 极大提升用户体验。
- 提供灵活的帧率设置接口,满足不同场景需求。
缺点
- 增加开发复杂度。
- 不支持低版本设备。
七、性能
使用 GPU Profiler 监测高刷新率下的应用性能,评估帧率与资源消耗的平衡点。
八、未来
未来,Android 系统或将支持更智能的动态帧率调整,结合 AI 技术预测用户操作,进一步优化资源分配。
本文从技术背景、实现原理到项目实战,为你详细解析了 Android 11 多刷新率支持。希望通过这些技术,让你的应用体验更上一层楼!
九、开发者选项
设置菜单中新增了一个开发者选项,它可以使用当前刷新率在屏幕上切换叠加层。新选项位于设置 > 系统 > 开发者选项 > 显示刷新频率下。
十、参考资料
以下是撰写本文时参考的技术资源,涵盖书籍、论文、官方网站和博客,帮助读者进一步深入理解多刷新率支持的实现与优化。
官方文档
-
Android Developers Documentation
- 官方多刷新率支持文档
Android 官方提供的多刷新率支持指南,详细介绍了功能组成、API 使用方法和平台支持。
- 官方多刷新率支持文档
-
Surface API Reference
- Surface.setFrameRate
提供 Surface 类的完整 API 说明,包含帧率设置和兼容性选项。
- Surface.setFrameRate
-
NDK Documentation
- NDK API for Refresh Rate
介绍了通过 NDK 实现刷新率动态调整的相关工具和方法。
- NDK API for Refresh Rate
书籍
-
《Android 高级编程》
作者:[Joseph Annuzzi Jr., Lauren Darcey, Shane Conder]
讲解 Android 开发高级特性,包括硬件抽象层和系统架构,适合了解多刷新率支持的底层实现。 -
《Android 深入理解与实战》
作者:邓凡平
提供 Android 系统机制与应用开发的深入剖析,是学习 Android 系统级开发的好工具书。 -
《Graphics Programming Black Book》
作者:Michael Abrash
虽然主要针对图形编程基础,但对优化刷新率和性能调优有很大的启发。
论文
-
“Variable Refresh Rate Displays and Their Impact on Visual Performance”
描述多刷新率技术在视觉效果和用户体验中的重要性,涵盖了刷新率动态调整的研究数据。 -
“Adaptive Refresh Rate Mechanisms in Modern Display Technologies”
探讨了现代显示技术中自适应刷新率机制的设计与实现。
技术博客
-
Android Developers Blog: New Features in Android 11
Android 官方博客详细介绍了 Android 11 的新特性,包括多刷新率支持。 -
Medium: Implementing High Refresh Rates in Android Apps
技术博主在实际项目中如何实现动态刷新率设置的案例分享。 -
CSDN: 动态刷新率实现的坑与优化
提供在实际开发过程中遇到的问题及解决方案。
社区资源
-
Stack Overflow
- Handling Variable Refresh Rates
解答开发者在多刷新率开发中常见的问题,拥有丰富的社区实践经验。
- Handling Variable Refresh Rates
-
GitHub
- 示例代码仓库:Dynamic Refresh Rate Demo
提供完整的多刷新率实现样例代码,可直接下载学习。
- 示例代码仓库:Dynamic Refresh Rate Demo
工具与环境
-
Android Studio Arctic Fox 或更高版本
支持 Android 11 开发的 IDE。 -
设备
- 测试设备需支持多刷新率,如 Pixel 5、Samsung Galaxy S 系列等。
-
工具
adb shell
:用于调试和检查设备支持的刷新率。Choreographer
:实现帧同步的重要工具。
这些参考资料涵盖了理论知识、实践经验和代码示例,帮助开发者全面掌握多刷新率技术的实现与优化。如果你有更多推荐或想法,欢迎在评论区留言交流! 😊
文章结尾
欢迎关注我们的 GongZhongHao:码农的乌托邦,程序员的精神家园!获取更多技术干货,我们一起提升代码水平!
相关文章:

Android系统开发(十五):从 60Hz 到 120Hz,多刷新率进化简史
引言 欢迎来到“帧率探索实验室”!今天,我们要聊聊 Android 11 中对多种刷新率设备的支持。你可能会问:“这和我写代码有什么关系?”别急,高刷新率不仅仅让屏幕更顺滑,还会直接影响用户体验。想象一下&…...

js判断一个数组对象中是否有相同的值
let userTitleLevelList[{title:医生,code:20},{title:老师,code:21}]; 如果一个数组对象格式如上面。如果有一样的对象就提示。即:title和code都是一样的内容、 const hasDuplicate userTitleLevelList.some((item, index, array) > { return array.filter(…...

基于深度学习的视觉检测小项目(十五) 用户的登录界面
用户管理离不开的是消息框(QMessageBox)和对话框(QDialog),比如对话框用于用户名和密码输入,消息框用于提示登录成功、密码错误。 • 基础知识:PySide6(PyQT5)的常用对话…...

redis-排查命中率降低问题
1.命中率降低带来的问题 高并发系统,当命中率低于平常的的运行情况,或者低于70%时,会产生2个影响。 有大量的请求需要查DB,加大DB的压力;影响redis自身的性能 不同的业务场景,阈值不一样,一般…...

ui文件转py程序的工具
源博客连接: PyCharm中利用外部工具uic转成的py文件,里面全是C代码,并非python类型的代码,导致大量报错。。。_pyside6-uic为什么把ui转为了c-CSDN博客 如果想把ui文件转为py文件,首先设置pycharm的外部工具…...

Alluxio 联手 Solidigm 推出针对 AI 工作负载的高级缓存解决方案
作者:Wayne Gao, Yi Wang, Jie Chen, Sarika Mehta Alluxio 作为全球领先的 AI 缓存解决方案供应商, 提供针对 GPU 驱动 AI 负载的高速缓存。其可扩展架构支持数万个节点,能显著降低存储带宽的消耗。Alluxio 在解决 AI 存储挑战方面的前沿技…...

Oracle 数据库常见字段类型大全及详细解析
在工作期间会遇到数据库建表的业务,经常会使用复制粘帖等操作,而不清楚数据库的字段类型。本文记录了 Oracle 数据库常见字段类型,根据不同的数据需求,可以选择不同的字段类型来存储数据。 文章目录 一、字符类型(Char…...

U3D的.Net学习
Mono:这是 Unity 最初采用的方式,它将 C# 代码编译为中间语言 (IL),然后在目标平台上使用虚拟机 (VM) 将其转换为本地机器码执行。 IL2CPP:这是一种较新的方法,它会将 C# 代码先编译为 C 代码,再由 C 编译器…...

Tomcat下载配置
目录 Win下载安装 Mac下载安装配置 Win 下载 直接从官网下载https://tomcat.apache.org/download-10.cgi 在圈住的位置点击下载自己想要的版本 根据自己电脑下载64位或32位zip版本 安装 Tomcat是绿色版,直接解压到自己想放的位置即可 Mac 下载 官网 https://tomcat.ap…...

adb常用指令(完整版)
1、adb devices 查看是否连接到设备 2、adb install [-r] [-s] 安装app,-r强制,-s安装sd卡上 3、adb uninstall [-k] 卸载app,-k保留配置和参数 4、adb push 把本地文件上传设备 5、adb pull 下载文件到本地 6、cd D:\sdk\platform-tool…...

大数据学习(36)- Hive和YARN
&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博主哦ᾑ…...

C# ASP.NET MVC项目内使用ApiController
1.在App_Start文件夹新建WebApiConfig.cs文件,建立webApi路由的注册方法。 using System.Web.Http;namespace PrivilegeManager {public class WebApiConfig{public static void Register(HttpConfiguration config){config.MapHttpAttributeRoutes();config.Route…...

Kafka 入门与应用实战:吞吐量优化与与 RabbitMQ、RocketMQ 的对比
前言 在现代微服务架构和分布式系统中,消息队列作为解耦组件,承担着重要的职责。它不仅提供了异步处理的能力,还能确保系统的高可用性、容错性和扩展性。常见的消息队列包括 Kafka、RabbitMQ 和 RocketMQ,其中 Kafka 因其高吞吐量…...

“推理”(Inference)在深度学习和机器学习的语境
“推理”(Inference)在深度学习和机器学习的语境中,是指使用经过训练的模型对新数据进行预测的过程。将其简单地理解为“模型的应用阶段”。在这一阶段,我们不再进行模型训练,而是利用已训练好且保存下来的模型来获取对…...

字节腾讯阿里大厂面经汇总:Java集合(容器)大厂面试题及参考答案
ArrayList 的扩容机制以及删除操作的时间复杂度 ArrayList 是 Java 中非常常用的一个集合类,它是基于数组实现的动态数组。当我们创建一个 ArrayList 时,如果不指定初始容量,它会有一个默认的初始容量(通常是 10)。当我们向 ArrayList 中添加元素时,如果元素的数量达到了…...

数据结构(初阶)(一)----算法复杂度
算法复杂度 算法复杂度数据结构算法算法效率复杂度的概念 数据结构 数据结构(Data Structure)是计算机存储、组织数据的⽅式,指相互之间存在⼀种或多种特定关系的数据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤,所以我们要学各式各样的数据结…...

构建高效稳定的网络环境
概述 网络技术是当今IT行业的重要组成部分,构建高效稳定的网络环境对于企业、个人和互联网发展至关重要。本文将探讨网络技术中的关键要素,包括网络协议、网络架构、网络安全和网络优化,并提供实用的技巧和最佳实践,以帮助您构建…...

使用Edge打开visio文件
使用Edge打开visio文件 打开Edge浏览器搜索‘vsdx edge’ 打开第一个搜索结果 Microsoft Support 根据上述打开的页面进行操作 第一步:安装Visio Viewer 第二步:添加注册表 桌面新增文本文件,将下面的内容放入新建文本中,修…...

ChatGPT Prompt 编写指南
一、第一原则:明确的意图 你需要明确地表达你的意图和要求,尽可能具体、描述性、详细地描述所需的上下文、你期望的结果等。你的要求越明确,越有希望获得你想要的答案。 糟糕的案例 ❌ 写一首关于 OpenAI 的诗。 更好的案…...

蚁群算法 (Ant Colony Optimization) 算法详解及案例分析
蚁群算法 (Ant Colony Optimization) 算法详解及案例分析 目录 蚁群算法 (Ant Colony Optimization) 算法详解及案例分析1. 引言2. 蚁群算法 (ACO) 算法原理2.1 蚂蚁觅食行为2.2 算法步骤2.3 数学公式3. 蚁群算法的优势与局限性3.1 优势3.2 局限性4. 案例分析4.1 案例1: 旅行商…...

安卓动态设置Unity图形API
命令行方式 Unity图像api设置为自动,安卓动态设置Vulkan、OpenGLES Unity设置 安卓设置 创建自定义活动并将其设置为应用程序入口点。 在自定义活动中,覆盖字符串UnityPlayerActivity。updateunitycommandlineararguments (String cmdLine)方法。 在该方法中,将cmdLine…...

通信协议—WebSocket
一、WebSocket编程概念 1.1 什么是WebSocket WebSocket 是一种全双工通信协议,允许在客户端(通常是浏览器)和服务器之间建立持久连接,以实现实时的双向通信。它是 HTML5 标准的一部分,相比传统的 HTTP 请求ÿ…...

helm推送到harbor私有库--http: server gave HTTP response to HTTPS client
harbor私有库访问的是http模式 harbor 2.8版本以上可以存储helm镜像 docker镜像推送的时候需要docker端配置insecure-registries 发现helm推送只能在harbor部署的本机使用localhost才能推送成功,即 helm push xxx.tgz oci://localhost:80/library 使用helm pus…...

数据结构——实验一·线性表
海~~欢迎来到Tubishu的博客🌸如果你也是一名在校大学生,正在寻找各种变成资源,那么你就来对地方啦🌟 Tubishu是一名计算机本科生,会不定期整理和分享学习中的优质资源,希望能为你的编程之路添砖加瓦⭐&…...

快速搭建深度学习环境(Linux:miniconda+pytorch+jupyter notebook)
本文基于服务器端环境展开,使用的虚拟终端为Xshell。 miniconda miniconda是Anaconda的轻量版,仅包含Conda和Python,如果只做深度学习,可使用miniconda。 [注]:Anaconda、Conda与Miniconda Conda:创建和管…...

OpenCV相机标定与3D重建(66)对立体匹配生成的视差图(disparity map)进行验证的函数validateDisparity()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 使用左右检查来验证视差。矩阵 “cost” 应该由立体对应算法计算。 cv::validateDisparity 函数是 OpenCV 库中用于对立体匹配生成的视差图&…...

2025年新开局!谁在引领汽车AI风潮?
汽车AI革命已来。 在2025年伊始开幕的CES展上,AI汽车、AI座舱无疑成为了今年汽车行业的最大热点。其中不少车企在2025年CES上展示了其新一代AI座舱,为下一代智能汽车的人机交互、场景创新率先打样。 其中,东软集团也携带AI驱动、大数据支撑…...

Spring自定义BeanPostProcessor实现bean的代理Java动态代理知识
上文:https://blog.csdn.net/qq_26437925/article/details/145241149 中大致了解了spring aop的代理的实现,其实就是有个BeanPostProcessor代理了bean对象。顺便复习下java代理相关知识 目录 自定义BeanPostProcessor实现aopJava动态代理知识动态代理的几…...

三篇物联网漏洞挖掘综述
由于物联网设备存在硬件资源受限、硬件复杂异构, 代码、文档未公开的问题, 物联网设备的漏洞挖掘存在较大的挑战: 硬件资源受限性: 通用动态二进分析技术需要在运行程序外围实施监控分析。由于物联网设备存储资源(存储)的受限性,…...

Pytorch深度学习指南 卷I --编程基础(A Beginner‘s Guide) 第1章 一个简单的回归
本章正式开始使用pytorch的接口来实现对应的numpy的学习的过程,来学习模型的实现,我们会介绍numpy是如何学习的,以及我们如何一步步的通过torch的接口来实现简单化的过程,优雅的展示我们的代码,已经我们的代码完成的事…...