简单网站建设协议书,商城火车站,本机快速做网站,临城网站文章目录 知识回顾前言源码分析1. 渲染过程2. 分析工具3. 优化方法合理使用const关键词合理使用组件管理着色器编译垃圾 知识回顾
前言
项目迭代开发一定程度后#xff0c;性能优化是重中之重#xff0c;其中包括了包体积#xff0c;UI 渲染、交互等多个方面。 通过 Flutt… 文章目录 知识回顾前言源码分析1. 渲染过程2. 分析工具3. 优化方法合理使用const关键词合理使用组件管理着色器编译垃圾 知识回顾
前言
项目迭代开发一定程度后性能优化是重中之重其中包括了包体积UI 渲染、交互等多个方面。 通过 Flutter 应用的混淆为入口我们主要探讨了UI 渲染的优化。
其中就会涉及到一个非常关健的概念 ——「FPSFrame 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.cnhttps://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 改变透明度如要作用于一个图片的时候可以直接使用透明的图片或者直接使用 ContainerContainer(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-skslflutter run --profile --cache-sksl --purge-persistent-cache
该参数可能会删除 SkSL 着色器捕获的较旧的非 SkSL着色器缓存因此只能在第一次运行时使用 --cache-sksl。
在不同平台上可以执行以下命令使用 SkSL 预热功能构建应用程序
flutter build apk — bundle-sksl-path flutter_01.sksl.json