走近科学,探究阿里闲鱼团队通过数据提升Flutter体验的真相

简介: 闲鱼客户端的flutter页面已经服务上亿级用户,这个时候Flutter页面的用户体验尤其重要,完善Flutter性能稳定性监控体系,可以及早发现线上性能问题,也可以作为用户体验提升的衡量标准。那么Flutter的性能到底如何?是否像官方宣传的那么丝滑?Native的性能指标是否可以用来检测Flut...

作者:闲鱼技术-三莅

背景

闲鱼客户端的flutter页面已经服务上亿级用户,这个时候Flutter页面的用户体验尤其重要,完善Flutter性能稳定性监控体系,可以及早发现线上性能问题,也可以作为用户体验提升的衡量标准。那么Flutter的性能到底如何?是否像官方宣传的那么丝滑?Native的性能指标是否可以用来检测Flutter页面?下面给大家分享我们在实践中总结出来的Flutter的性能稳定性监控方案。

目标

过度的丢帧从视觉上会出现卡顿现象,体现在用户滑动操作不流畅;页面加载耗时过长容易中断操作流程;Flutter部分exception会导致发生异常代码后面的逻辑没有走到从而造成逻辑bug甚至白屏。这些问题很容易考验用户耐心,引起用户反感。

所以我们制定以下三个指标作为线上Flutter性能稳定性标准:

  1. 页面滑动流畅度
  2. 页面加载耗时(首屏时长+可交互时长)
  3. Exception率

最终目标是让这些数据指标驱动Flutter用户体验升级。

页面滑动流畅度

我们先大概了解下屏幕渲染流程:CPU先把UI对象转变GPU可以识别的信息存储进displaylist列表,GPU执行绘图指令来执行displaylist,取出相应的图元信息,进行栅格化渲染,显示到屏幕上,这样一个循环的过程实现屏幕刷新。

闲鱼客户端采用的Native、Flutter混合技术方案,Native页面FPS监控采用集团高可用方案,Flutter页面是否可以直接采用这套方案监控?

普遍的FPS检测方案Android端采用的是Choreographer.FrameCallBack,IOS采用的是CADisplayLink注册的回调,原理是类似的,在每次发出Vsync信号,并且CPU开始计算的时候执行到对应的回调,这个时候表示屏幕开始一次刷新,计算固定时间内屏幕渲染次数来得到fps。(这种方式只能检测到CPU卡顿,对于GPU的卡顿是无法监控到的)。由于这两种方法都是在主线程做检测处理,而flutter的屏幕绘制是在UI TaskRunner中进行,真正的渲染操作是在GPU TaskRunner中。
这里我们得出结论:Native的FPS检测方法并不适用于Flutter。

上图显示了Performance Overlay模式下的帧率统计,可以看到,Flutter分开计算GPU 和UI TaskRunner。UI Task Runner被Flutter Engine用于执行Dart root isolate代码,GPU Task Runner被用于执行设备GPU的相关调用。通过对flutter engine源码分析,UI frame time是执行window.onBeginFrame所花费的总时间。GPU frame time是处理CPU命令转换为GPU命令并发送给GPU所花费的时间。

这种方式只能在debug和profile模式下开启,没有办法作为线上版本的fps统计。但是我们可以通过这种方式获得启发,通过监听Flutter页面刷新回调方法handleBeginFrame()、handleDrawFrame()来计算实际FPS。

具体实现方式:

注册WidgetsFlutterBinding监听页面刷新回调handleBeginFrame()、handleDrawFrame()

handleBeginFrame: Called by the engine to prepare the framework to produce a new frame.
handleDrawFrame: Called by the engine to produce a new frame.

通过计算handleBeginFrame和handleDrawFrame之间的时间间隔计算帧率,主要流程如下图:

效果

到这里,我们完成Flutter中页面帧率的统计,这种方式统计的是UI TaskRunner中的CPU操作耗时,GPU操作在Flutter引擎内部实现,要修改引擎来监控完整的渲染耗时,我们目前大部分的场景没有复杂到gpu卡顿,问题主要还是集中在CPU,所以说可以反应出大部分问题。从线上数据来看,release模式下Flutter的流畅度还是蛮不错的,ios的主要页面均值基本维持在50fps以上,android相对ios略低。这里需要注意的是帧率的均值fps在反复滑动过程中会有一个稀释效果,导致一些卡顿问题没有暴露出来,所以除了fps均值,需要综合掉帧范围、卡顿秒数、滑动时长等数据才能反应出页面流畅度情况。

页面加载时长

集团内部高可用方案统计Native页面加载时长是通过容器初始化后开启定时器在容器layout的时候检查屏幕渲染程度,计算可见组件的屏幕覆盖率,满足条件水平>60%,垂直>80%以上认为满足页面填充程度,再检查主线程心跳判断是否加载完成

再来看看weex页面加载流程和统计数据的定义

Weex的页面刷新稳定定义:屏幕内view渲染完成且view树稳定的时间

具体实现:当屏幕内发生view的add/rm操作时,认为是可交互点,记录数据。直到没有再发生为止。

在概念上Flutter和weex的首屏时长和可交互时长并不完全一致,Flutter之所以选择从路由跳转开始计算时长主要是因为这种计算方式更贴近用户体验,可以获取更多的问题信息,比如路由跳转的时长问题等。

Flutter的可交互时长end点采用的算法与native一致,可见组件满足页面填充程度并且完成心跳检查的情况下任务可交互,另外对于一些比较空的页面,组件面积小,无法达到水平>60%,垂直>80%的条件,就用交互前最后一次Frame刷新时间点作为end点。

具体流程如下图:

效果

由于debug模式采用的JIT编译,debug模式下体验加载时长偏长,但是release模式下的AOT编译时长明显缩短很多,整体页面加载时长还是要优于weex。

Exception率

Flutter部分exception/error 会导致代码后面的逻辑没有走到造成页面或逻辑bug,所以flutter的exception需要作为稳定性的标准之一

定义

FlutterException率 = exception发生次数 / flutter页面PV

分子:exception发生次数(已过滤掉白名单)

Flutter内部assert、try-catch和一些异常逻辑的地方会统一调用FlutterError.onError

通过重定向FlutterError.onError到自己的方法中监测exception发生次数,并上报exception信息

分母:flutter页面PV

具体实现如下:

Future<Null> main() async {
  FlutterError.onError = (FlutterErrorDetails details) async {
    Zone.current.handleUncaughtError(details.exception, details.stack);
  };
 
  runZoned<Future<Null>>(() async {
    runApp(new HomeApp());
  }, onError: (error, stackTrace) async {
    await _reportError(error, stackTrace);
  });
}

其中,FlutterError.onError只会捕获Flutter framework层的error和exception,官方建议将这个方法按照自己的exception捕获上报需求定制。在实践过程中,我们遇到很多不会对用户体验产生任何影响的exception会被频繁触发,这类没有改善意义的exception可以添加白名单过滤上报。

效果

有了线上exception的监控,可以及早发现隐患,获取问题堆栈信息,方便定位bug,提示整体稳定性

总结

到这里,我们完成Flutter页面滑动流畅度、页面加载时长和Exception率的统计,对于Flutter的性能有一个具体的数字化标准,对以后的用户体验提升和性能问题排查提供基础。目前闲鱼客户端的商品详情页和主发布页已经全量Flutter化,感兴趣的同学可以体验下这两个页面和其他页面的性能差异,最后欢迎大家提供反馈和建议。

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
4月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
460 4
|
4月前
|
缓存 监控 前端开发
优化 Flutter 应用启动速度的策略,涵盖理解启动过程、资源加载优化、减少初始化工作、界面布局优化、异步初始化、预加载关键数据、性能监控与分析等方面
本文探讨了优化 Flutter 应用启动速度的策略,涵盖理解启动过程、资源加载优化、减少初始化工作、界面布局优化、异步初始化、预加载关键数据、性能监控与分析等方面,并通过案例分析展示了具体措施和效果,强调了持续优化的重要性及未来优化方向。
136 10
|
1月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
178 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
在 Flutter 中如何使用 ChangeNotifierProvider 实现数据共享?
在 Flutter 中如何使用 ChangeNotifierProvider 实现数据共享?
|
4月前
深入理解Flutter鸿蒙next版本 中的Widget继承:使用extends获取数据与父类约束
本文详细介绍了Flutter中如何通过继承其他Widget来创建自定义组件。首先解释了Widget继承的基本概念,包括StatelessWidget和StatefulWidget的区别。接着通过具体示例展示了如何继承StatelessWidget和StatefulWidget,并在子类中访问父类的build方法和状态。最后,结合多个自定义Widget展示了如何在实际应用中灵活使用继承和组合来构建复杂的UI。
129 8
|
4月前
|
JavaScript API 开发工具
<大厂实战场景> ~ Flutter&鸿蒙next 解析后端返回的 HTML 数据详解
本文介绍了如何在 Flutter 中解析后端返回的 HTML 数据。首先解释了 HTML 解析的概念,然后详细介绍了使用 `http` 和 `html` 库的步骤,包括添加依赖、获取 HTML 数据、解析 HTML 内容和在 Flutter UI 中显示解析结果。通过具体的代码示例,展示了如何从 URL 获取 HTML 并提取特定信息,如链接列表。希望本文能帮助你在 Flutter 应用中更好地处理 HTML 数据。
171 1
|
4月前
|
JSON Dart 数据格式
<大厂实战场景> ~ flutter&鸿蒙next处理后端返回来的数据的转义问题
在 Flutter 应用开发中,处理后端返回的数据是常见任务,尤其涉及转义字符时。本文详细探讨了如何使用 Dart 的 `dart:convert` 库解析包含转义字符的 JSON 数据,并提供了示例代码和常见问题的解决方案,帮助开发者有效处理数据转义问题。
220 0
|
7月前
|
前端开发
Flutter快速实现自定义折线图,支持数据改变过渡动画
Flutter快速实现自定义折线图,支持数据改变过渡动画
160 4
|
7月前
|
Web App开发 新零售 前端开发
Flutter技术实践问题之阿里集团内Flutter体系化建设如何解决
Flutter技术实践问题之阿里集团内Flutter体系化建设如何解决
61 1
|
7月前
|
开发者 监控 开发工具
如何将JSF应用送上云端?揭秘在Google Cloud Platform上部署JSF应用的神秘步骤
【8月更文挑战第31天】本文详细介绍如何在Google Cloud Platform (GCP) 上部署JavaServer Faces (JSF) 应用。首先,确保已准备好JSF应用并通过Maven构建WAR包。接着,使用Google Cloud SDK登录并配置GCP环境。然后,创建`app.yaml`文件以配置Google App Engine,并使用`gcloud app deploy`命令完成部署。最后,通过`gcloud app browse`访问应用,并利用GCP的监控和日志服务进行管理和故障排查。整个过程简单高效,帮助开发者轻松部署和管理JSF应用。
86 0

热门文章

最新文章

  • 1
    【Flutter 开发必备】AzListView 组件全解析,打造丝滑索引列表!
    30
  • 2
    flutter3-wetrip跨平台自研仿携程app预约酒店系统模板
    34
  • 3
    通过外部链接启动 Flutter App(详细介绍及示例)
    32
  • 4
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    155
  • 5
    零基础构建即时通讯开源项目OpenIM移动端-Flutter篇
    101
  • 6
    flutter3-dart3-dymall原创仿抖音(直播+短视频+聊天)商城app系统模板
    60
  • 7
    【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    175
  • 8
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    55
  • 9
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
    82
  • 10
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    178