【Android常见问题(五)】- Flutter项目性能优化

文章目录

  • 知识回顾
  • 前言
  • 源码分析
    • 1. 渲染过程
    • 2. 分析工具
    • 3. 优化方法
      • 合理使用const关键词
      • 合理使用组件
      • 管理着色器编译垃圾


知识回顾

前言

项目迭代开发一定程度后,性能优化是重中之重,其中包括了包体积,UI 渲染、交互等多个方面。
通过 Flutter 应用的混淆为入口,我们主要探讨了UI 渲染的优化。

其中就会涉及到一个非常关健的概念 ——「FPS,Frame Per Second」即「每秒展示帧数」,它代表了应用的流畅度。

我们知道,动画和物体动态的运动都是由在一段时间内一系列连续变化的静态帧构成的。

在考虑应用的渲染性能时,我们就是在试图分析应用每秒渲染的帧数。

从物理角度看,对于连续的一系列图像帧,人脑会根据眼睛发出的视觉信号做出反应,一个个静态帧的切换到达一定速度后,就可以欺骗我们的大脑,让我们以为它们是连续的,FPS 就是图像帧切换的速度单位。

因此有人说,物体运动的概念其实就是一种思维的束缚。

当 FPS 达到 10-12 时,大脑便可以感知运动,此时并不流畅,达到 24 FPS 时,人眼就能看到流畅的运动了,但是在电影和视频中,则至少需要每秒 60 帧的速度才可以使人的大脑轻松感知到流畅地运动。
在这里插入图片描述
1000ms / 60 frames = 16.666 ms/frame

我们需要在 16.66 毫秒内完成整个帧的计算,布局和渲染,否则不流畅,就需要掏出我们的 24K 合金双摄眼,找到优化点,让应用保持流畅。


源码分析

1. 渲染过程

Flutter 应用的每一帧都由框架层和引擎层互相协作完成。

最初,某些外部事件(如手势,网络等)或者异步任务会导致屏幕更新,该消息消息页会通知到引擎层。

Flutter 框架层会拦截了该请求,执行 Tickers 相关的任务(如动画)。

这些任务也可能会重新发出一个请求,以供以后的帧渲染。(如动画暂停后再继续,需要在以后的阶段接收另一个 Begin 帧)。

然后,引擎层就可以开始做屏幕渲染工作了,但在开始之前,Flutter 框架依然会拦截该请求,并根据当前的组件结构和尺寸大小计算出更新布局、绘制相关的所有数据。

完成这些任务后,如果最终确定真的要在屏幕上绘制一些东西,它就会将需要渲染的新数据发送到 Flutter Engine,做最终的屏幕更新。

在这里插入图片描述

整个过程都在 Flutter 的 UI 线程中运行,如若阻塞,就会卡顿。

通常,应用开发者不需要关心引擎层的逻辑,但并不意味着我们不需要关心渲染性能。

引擎层的功能其实也是单一的,他只是拿到框架层的数据去做渲染而已。但是框架层是由我们控制的,我们所写的每一个组件都在框架层之上。

如何将传递给引擎层的更新数据做到最优,就是渲染优化时我们需要考虑的问题。

这些更新数据就是由 Flutter 中重要的三棵树生成的,建议不熟悉的读者去回看之前的这篇文章。

我们需要做的就是让 Flutter 中重建组件的个数尽量少。

2. 分析工具

在 Android Studio 中,找到 Flutter Performance (View > Tool Windows > Flutter Performance),就可以直接看到正在重建的 widget 数量。

这里,勾选 Show widget rebuild information 复选框,此功能也能够帮助你检测帧的渲染和显示时间是否超过 16ms。

3. 优化方法

合理使用const关键词

const 您可以通过将其附加到Widget的构造函数来抑制Widget的重建(它与Widget缓存时的状态相同)。

构建组件时使用 const 关键词,可以抑制 widget 的重建。
const 在 Dart 中用于声明常量,应用到 widget 中就相当于告诉 Flutter,“我这个组件不会碎状态更新而改变了。”,因此达到了减少重建的效果。

使用 const 也需要注意如下几点:

当const 修饰类的构造函数时,它要求该类的所有成员都必须是final的。
const 变量只能在定义的时候初始化。
合理利用 const 关键词,可以在很大程度上优化应用的性能

合理使用组件

Flutter 实现的一些效果背后可能会使用 saveLayer() 这个代价很大的方法。
为什么 saveLayer 代价很大?
调用 saveLayer() 会开辟一片离屏缓冲区。将内容绘制到离屏缓冲区可能会触发渲染目标切换,这些切换在较早期的 GPU 中特别慢。

——来自 flutter.cn,https://flutter.cn/docs/testing/best-practices
如下这几个组件,底层都会触发 saveLayer() 的调用,同样也都会导致性能的损耗:

ShaderMask
ColorFilter
Chip,当 disabledColorAlpha != 0xff 的时候,会调用 saveLayer()。
Text,如果有 overflowShader,可能调用 saveLayer() ,
官方也给了我们一些非常需要注意的优化点:

由于 Opacity 会使用屏幕外缓冲区直接使目标组件中不透明,因此能不用 Opacity Widget,就尽量不要用。有关将透明度直接应用于图像的示例,请参见 Transparent image,比使用 Opacity widget 更快,性能更好。

要在图像中实现淡入淡出,请考虑使用 FadeInImage 小部件,该小部件使用 GPU 的片段着色器应用渐变不透明度。

很多场景下,我们确实没必要直接使用 Opacity 改变透明度,如要作用于一个图片的时候可以直接使用透明的图片,或者直接使用 Container:Container(color: Color.fromRGBO(255, 0, 0, 0.5))

Clipping 不会调用 saveLayer()(除非明确使用 Clip.antiAliasWithSaveLayer),因此这些操作没有 Opacity 那么耗时,但仍然很耗时,所以请谨慎使用。

要创建带圆角的矩形,而不是应用剪切矩形,请考虑使用很多 widget 都提供的 borderRadius属性。

管理着色器编译垃圾

有时候,应用中的动画首次运行时会看起来非常卡顿,但是运行多次之后便可以正常运行,这可能就是由于着色器编译混乱导致的。

在图形渲染,着色器相当于是在 GPU 运行的一组代码。想要达到 60fps,需要在 16 毫秒内绘制一个平滑的帧,但是在编译着色器时,它花费的时间可能比应该花费的时间更多,可能会接近几百毫秒,并且会导致丢失数十个帧,将 fps 从 60 降至 6。

解决方法
Flutter 1.20 之后,Flutter 为开发者提供了非常方便的一组命令行工具,由此开发人员可以使用 Skia Shader Language 格式收集最终用户可能需要的着色器, 一旦将 SkSL 着色器打包到应用程序中,当用户打开应用程序时,就会自动进行预编译。

运行应用,添加 --cache-sksl 参数捕获 SkSL 中的着色器:

flutter run --profile --cache-sksl

flutter run --profile --cache-sksl --purge-persistent-cache

该参数可能会删除 SkSL 着色器捕获的较旧的非 SkSL着色器缓存,因此只能在第一次运行时使用 --cache-sksl。

在不同平台上,可以执行以下命令,使用 SkSL 预热功能构建应用程序:

flutter build apk — bundle-sksl-path flutter_01.sksl.json

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/51627.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

码农该如何延长周末体验感

码农该如何延长周末体验感 码农该如何延长周末体验感 码农该如何延长周末体验感1.制定合理的工作计划:2.实践工作与生活的平衡:3.学习新技术或扩展知识领域4.参与开源项目或个人项目:5.与同事或朋友组织活动:6.自己写博客或者总结…

百万数据快速导入导出

百万数据快速导入 pom <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.0</version></dependency>Resourceprivate SalariesListener salariesListener;private ExecutorService…

求解方程x^2=a的根,不使用库函数直接求解(不动点迭代法)

首先可以将方程两边同时加上x&#xff0c;&#xff0c;这时候两边同时再除以1x&#xff0c;就得到了&#xff0c;变形为。&#xff08;变性后的迭代式不唯一&#xff0c;这里随便选取一个&#xff09; 当x是准确值的时候&#xff0c;两边应该是相等的&#xff0c;如果x是近似值…

【Git】分支管理之创建、切换、合并、删除分支以及冲突处理

目录 一、理解分支 二、创建、切换、合并分支 三、删除分支 四、冲突处理 五、合并模式 六、合并策略 七、Bug分支处理 八、强制删除分支 一、理解分支 master其实就是一个指针 &#xff0c;他指向的是主分支最近一次commit。我们可以创建新的分支&#xff0c;在新的分…

Arcgis之 KML/KMZ文件转shp

一般我们在Goole Earth上勾画的区域导出后都为KML或者KMZ格式的&#xff0c;但无法在arcgis等软件上直接应用&#xff0c;故需进行一定的转换 1.打开ArcMap&#xff0c;选择ArcToolbox->Conversion Tools->From KML->KML To Layer 得到如下结果&#xff08;由于本KML…

请问学JavaScript 前要学html 和css 吗?

前言 html和css可以理解为是一个网站的骨架和皮肤&#xff0c;这两部分做好后整个网站的外观展示的完成度基本就有了个90%左右&#xff0c;所以在学习js前是需要学习html和css 的&#xff0c;这两部分不用花特别多的时间&#xff08;虽然css如果想做一些非常炫酷的效果个人认为…

什么是SVM算法?硬间隔和软间隔的分类问题

SVM全称是supported vector machine(支持向量机)&#xff0c;即寻找到一个超平面使样本分成两类&#xff0c;并且间隔最大。 SVM能够执行线性或⾮线性分类、回归&#xff0c;甚至是异常值检测任务。它是机器学习领域最受欢迎的模型之一。SVM特别适用于中小型复杂数据集的分类。…

MobaXterm通过SSH访问Ubuntu服务器遇到的一个问题

在Windows下的MobaXterm界面配置完ubuntuIP以后显示access denied&#xff0c;排查发现是因为在ubuntu那边忘记安装了SSH Serve&#xff0c;安装过程如下&#xff1a; 第一步&#xff1a;安装所需包 让我们从打开终端输入一些必要命令开始。 注意&#xff0c;在安装新的包或…

SpringBoot统一异常处理和统一返回格式

上篇博客我们讲解了使用AOP来进行统一的用户登录判断&#xff0c;其实像这种功能统一且使用较多的地方&#xff0c;都可以用AOP来处理&#xff0c;除了统⼀的⽤户登录判断之外&#xff0c;AOP 还可以实现&#xff1a; 统⼀⽇志记录统⼀⽅法执⾏时间统计&#xff08;在性能优化…

机器学习:混合高斯聚类GMM(求聚类标签)+PCA降维(3维降2维)习题

使用混合高斯模型 GMM&#xff0c;计算如下数据点的聚类过程&#xff1a; Datanp.array([1,2,6,7]) 均值初值为: μ1,μ21,5 权重初值为: w1,w20.5,0.5 方差: std1,std21,1 K2 10 次迭代后数据的聚类标签是多少&#xff1f; 采用python代码实现&#xff1a; from scipy import…

人工智能-Dlib+Python实现人脸识别(人脸识别篇)

人脸识别流程 人脸检测,人脸数据提取:首先是检测到人脸保存人脸数据:可以保存到mysql数据库中mysql数据库连接mysql数据库安装mysql数据库操作设置人脸数据标签:(人脸名字),保存到数据库打开摄像头,检测到人脸,提取人脸数据:人脸数据与数据库中的数据对比,1、人脸检…

【图论】Prim算法

一.介绍 Prim算法是一种用于解决最小生成树问题的贪心算法。最小生成树问题是指在一个连通无向图中找到一个生成树&#xff0c;使得树中所有边的权重之和最小。 Prim算法的基本思想是从一个起始顶点开始&#xff0c;逐步扩展生成树&#xff0c;直到覆盖所有顶点。具体步骤如下…

用合成数据训练托盘检测模型【机器学习】

想象一下&#xff0c;你是一名机器人或机器学习 (ML) 工程师&#xff0c;负责开发一个模型来检测托盘&#xff0c;以便叉车可以操纵它们。 ‌你熟悉传统的深度学习流程&#xff0c;已经整理了手动标注的数据集&#xff0c;并且已经训练了成功的模型。 推荐&#xff1a;用 NSDT设…

【业务功能篇60】Springboot + Spring Security 权限管理 【终篇】

4.4.7 权限校验扩展 4.4.7.1 PreAuthorize注解中的其他方法 hasAuthority&#xff1a;检查调用者是否具有指定的权限&#xff1b; RequestMapping("/hello")PreAuthorize("hasAuthority(system:user:list)")public String hello(){return "hello Sp…

深度学习入门教程(1):用神经网络预测糖尿病病例Predict Diabetes Cases with Neural Networks

本深度学习入门教程是在polyu HPCStudio 启发以及资源支持下进行的&#xff0c;在此也感谢polyu以及提供支持的老师。 大纲&#xff08;what will you learn from this project&#xff09; 1&#xff1a;What are neural networks&#xff1f; 2&#xff1a;Why use neural …

3D 渲染技巧-如何创建高质量写实渲染?

掌握创建高质量建筑渲染和任何 3D 渲染的艺术是一项复杂且需要技巧的工作&#xff0c;通常需要多年的经验和实践。实现逼真的结果需要仔细考虑众多因素&#xff0c;并避免可能导致缺乏真实性的假渲染效果的常见错误。 避免常见错误 - 提升渲染游戏的技巧 在追求创建真正逼真的…

从零开始学习CTF——CTF是什么

引言&#xff1a; 从2019年10月开始接触CTF&#xff0c;学习了sql注入、文件包含等web知识点&#xff0c;但都是只知道知识点却实用不上&#xff0c;后来在刷CTF题才发现知识点的使用方法&#xff0c;知道在哪里使用&#xff0c;哪里容易出漏洞&#xff0c;可是在挖src漏洞中还…

Appium+python自动化(二十四) - 元素等待(超详解)

思考 在自动化过程中&#xff0c;元素出现受网络环境&#xff0c;设备性能等多种因素影响。因此元素加载的时间可能不一致&#xff0c;从而会导致元素无法定位超时报错&#xff0c;但是实际上元素是正常加载了的&#xff0c;只是出现时间晚一点而已。那么如何解决这个问题呢&am…

【业务功能篇57】Springboot + Spring Security 权限管理 【上篇】

4.权限管理模块开发 4.1 权限管理概述 4.1.1 权限管理的意义 后台管理系统中&#xff0c;通常需要控制不同的登录用户可以操作的内容。权限管理用于管理系统资源&#xff0c;分配用户菜单、资源权限&#xff0c;以及验证用户是否有访问资源权限。 4.1.2 RBAC权限设计模型 …

Scratch 教程 之 如何四舍五入保留一个小数到指定的数位

有些时候&#xff0c;我们需要四舍五入一个多位小数到指定的位&#xff0c;但scratch并没有这个积木&#xff0c;怎么做呢&#xff1f;我来教你&#xff5e; 我们创建一个函数&#xff0c;需要时调用就行了&#xff5e; 如图&#xff0c;创建一个带参函数&#xff0c;勾选"…
最新文章