- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
做线上帧率监控上报时,少不了需要弄明白如何通过代码获取实时帧率的需求,这篇文章通过图解配合Flutter性能调试工具的方式一步步通俗易懂地让你明白获取帧率的基础知识,以后再也不愁看不懂调试工具上指标了.
Flutter 中通过如下方式监听帧率,addTimingsCallback 涉及到帧调度知识,感兴趣可以看看这篇 Flutter 帧调度过程 .
这里重点说说 List<FrameTiming>.
addTimingsCallback 定义:
List<FrameTiming>可简单理解成: 引擎层到框架层的帧数据流.
List<FrameTiming>则表示一系列实时帧信息.
如点击屏幕按钮,引擎将传递系列帧信息到框架层:“框架层,屏幕发送了变化,准备回调数据更新了!”。如果用户未操作,addTimesCallback 则不会回调.
因此 , addTimesCallback(List<FrameTiming>)只有用户操作界面时参数才有值 .
List<FrameTiming>中 0 的位置是第一帧,last 是最新一帧。 最新的帧永远在最后面 .
通过这个单词不难猜测 Frame 表示帧,加上 Timing 可以理解成实时变化的帧。FrameTiming 是一个用来存储实时帧信息的 数据结构 .
FrameTiming 定义:
这里列了下我认为最重要的几个属性:
理解上述属性前需了解渲染相关知识,不清楚的可以看看 Vsync 机制 和 卡顿产生原因 .
核心思想 图像内容展示到屏幕的过程需要 CPU 和 GPU 共同参与。CPU 负责计算显示内容,比如视图的创建、布局计算、图片解码、文本绘制等。随后 CPU 会将计算好的内容提交到 GPU 去,由 GPU 进行变换、合成、渲染。之后 GPU 会把渲染结果提交到帧缓冲区去,等待下一次 VSync 信号到来时显示到屏幕上。由于垂直同步的机制,如果在一个 VSync 时间内,CPU 或者 GPU 没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变.
当在应用中操作时候,就会产生连续的帧,如图:
每两个柱形一起表示一帧:ui 表示 cpu 耗时,raster 表示 gpu 耗时.
每帧细化后如下图,其中标注 ①②③④ 对应 FrameTiming 中的四个主要属性。而其中:
同时可推导出 FrameTiming 中相关衍生变量与上述重点关注属性关系:
④-① = totalSpan:同步信号开始到栅格化时间 。
②-① = vsyncOverhead:同步信号接受后到 ui 构建之间延迟.
③-② = buildDuration:ui 构建过程总时间.
④-③ = rasterDuration:栅格化过程总时间.
通过代码验证 Flutter 调试工具 PerformanceOverlay 中 Timing 每帧 ui 值和 ration 值与 vsyncstart、buildstart、buildFinish、rasterStart、rasterFinish 关系.
输出:
代码中,11 行是 ui 构建 + 栅格化时间,17 行是 totalSpan 时间, 22 行中是 vsyncOverhead + ui 构建 + 栅格化时间 这个值最终和才等于 totalSpan 值.
这里有个误区, 网上很少人关注 totalSpan 与 buildDuration+rasterDuration 关系,好像默认就是相等的。其实, totalSpan 不等于 Timing 中 ui + raster 值 , 而是 Vsync 信号接受后构建之前延迟 vsyncOverhead+cpu 构建耗时 + gpu 耗时 , 。
通过上述案例和 totalSpan 定义很容易佐证这点:
核心思路 。
从原生数据中筛查最新关注帧数,其他都干掉.
如下,通过栈方式调换了存储方式更容易操作,然后将栈中老的干掉只保留最新的关注 100 条.
将位于不同帧的无效数据过滤掉.
如下,以刷新率为 60 举例,如果一帧之间的时间 > 16.6 *2,该帧就位于不同帧中,因为一帧最大时间也就是 16.6ms.
代码如下:
这里拆解下其中逻辑,方便理解.
有 5 帧,其中在实际绘制过程中 f① 和 f② 都是在正常时间范围内绘制,f③ 则会绘制耗时,跨越 2 帧.
假设 f①,f②,f③ 绘制总耗时为 P1, P2, P3 则:
理论绘制帧数 = (P1 / 16.6)+ 1 + (P2 / 16.6) + 1 + (P3 / 16.6) + 1 图中明显可以看到 P1 和 P2 < 16.6, 而 P3 > 16.6 *2 ,所有理论绘制帧数 = 0 +1 + 0 + 1 + 2 + 1 = 5.
实际绘制帧数 = 3 .
本来正常应该绘制 5 帧,但是实际绘制 3 帧,取比值表示实际绘制能力,根据 FPS≈ REFRESH*RATE * 实际绘制帧数 / 理论绘制帧数 。 即 FPS = 3 _ 60 / 5.
上面代码在刷新率为 60HZ 的手机上每秒绘制帧时间为 16.6 是没有问题的,但是如果在其他帧率的手机上,比如 90HZ(OnePlus 7 Pro), 120HZ(Redmi K30)上就会存在问题.
思路:通过通道获取各系统提供的刷新率获取方式,然后更新上述代码中的刷新率.
在 Android 和 ios 平台提供了获取帧率的方法.
定义接口 。
本文重点讲解了 FrameTiming 结构在帧显示过程中的对应关系,图解获取准确帧的算法,最后完善了获取帧的逻辑.
总体来说网上能搜到的我这里都有,在学习过程中遇到 FrameTiming 结构和帧率计算方法这两个点觉得不好理解,不够系统,就重点介绍争取深入浅出表达出来。不足之处还望各位大佬指出,谢谢! 。
如果觉得文章对你有帮助, 点赞、收藏、关注、评论 ,一键四连支持,你的支持就是我创作最大的动力.
❤️ 本文原创 听蝉 公众号: 码里特别有禅 欢迎关注原创技术文章第一时间推送 ❤️ 。
PS: 文中所有源码获取方式:公众号后台回复 “fps” 。
如何代码获取 Flutter APP 的 FPS - Yrom's 。
Flutter 如何更加准确地获取 FPS | 区长 。
Flutter 性能计算之流畅性 fps 计算 - 简书 。
allenymt/flutter_fps: flutter Fps 的两种监听方案 。
如果觉得文章对你有帮助, 点赞、收藏、关注、评论 ,一键四连支持,你的支持就是我创作最大的动力.
❤️ 本文原创 听蝉 公众号: 码里特别有禅 欢迎关注原创技术文章第一时间推送 ❤️ 。
最后此篇关于Flutter帧率监控|由浅入深,详解获取帧率的那些事的文章就讲到这里了,如果你想了解更多关于Flutter帧率监控|由浅入深,详解获取帧率的那些事的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试从flutter应用程序构建apk,但出现此错误: Note: /mnt/Software/Linux/Flutter/flutter/.pub-cache/hosted/pub.dartl
我有一个名为 X 的较大应用程序,还有另一个名为 Y 的较小应用程序。他们现在彼此分开,并且工作正常。我想将应用程序 Y 集成到 X 中。我想将 Y 的代码放入 X 项目中,但它们应该有不同的 Mai
在android Studio中选择Create New Flutter Project,出现如下4个选项。 Flutter 应用程序 Flutter 插件 Flutter 包 flutter 模块
我看到我的 flutter 项目生成了一个文件 ios/Flutter/Flutter.podspec ,这个文件有什么用? 如果它与生成的 Flutter.framework 有关? 我应该将它包含
我尝试过的 在包含flutter SDK的位置添加/编辑.bash_profile.rtf文件。 导出PATH = / Users / temur / Documents / Projects / F
Flutter 日志会打印数千个详细/垃圾邮件日志。 我正在尝试调试一个复杂的应用程序,但是打印太冗长了,以至于我很难找到我自己打印的东西。 有没有办法禁用详细? 就像是: Logger.level.
在flutter 1.22更新之后,我在Lineargradient colors属性中遇到错误,这给我一个错误,即未定义名称colors参数。.在Android中更新flutter和flutter插
在下面的代码 widget.hintText 中给出错误,我试图将日期选择器作为单独的组件,并在从其他文件调用它时动态传递提示文本值。 import 'package:date_field/date_
在下面的代码 widget.hintText 中给出错误,我试图将日期选择器作为单独的组件,并在从其他文件调用它时动态传递提示文本值。 import 'package:date_field/date_
Flutter 1.0 发布后,我正在按照步骤搭建 Flutter 开发环境。 在步骤中(如所附屏幕截图所示),它说要更新 $PATH 两次,一次使用 flutter 工具的路径 export PAT
我有一个用 flutter 编写的移动应用程序,我想将其转换为 flutter_web 应用程序(集成 flutter_web 尚不可用)。我目前遇到包裹问题。 我已按照本网站中列出的说明进行操作 h
如何向我的 Flutter 路由添加自定义转换?这是我目前的路线结构。 class MyApp extends StatelessWidget { // This widget is the
我正在尝试通过 URL 在 webview 中显示网页。我试过 flutter_webview_plugin 插件,但是当我在浏览器上运行项目时它不起作用。 在 flutter web applica
我正在使用 animatedContainer 在按下按钮时显示 listView.builder()。这是一个要显示的简单子(monad)列表,但问题是我不知道 ListView 构建器的高度会传递
我目前正在我的应用程序中制作渐变背景动画......我正在使用 lottie 动画的帮助下这样做!我试图将它封装在一个容器中并成功地做到了。但是有一个问题,尽管我将高度更改为大于 2000 的东西,但
美好的一天! 我无法弄清楚如何使用 google 标签管理器设置 flutter。我找到了 this package包括标签管理器 api。但是我不知道如何正确配置它。 (在网络上我只需要复制粘贴一个
我的购物车模型如下 class Cart { String description; double unitCost; double amount; int quantity; S
在 Flutter 应用程序中,我想为在线托管的资源(图像、视频等)实现缓存。 我希望它能在原生平台 (Android/iOS)(例如使用文件系统)和网络(例如使用 IndexedDB)上运行。 Fl
我写了一个页面,在顶部一切都很好,应该是这样。在底部我有一个事件的历史。我的容器的宽度是自动确定的(取决于屏幕的宽度),而高度 - 不,在不同的设备上有不同的高度(底部的缩进是不同的)。是否可以自动确
我正在处理一个页面,其中有一些字段,例如 textfield 和 slider。在页面的末尾必须有一个用于进行下一步的按钮,该按钮被包裹在 Align 中以在页面之间具有固定位置。 另一方面,resi
我是一名优秀的程序员,十分优秀!