【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-skslflutter run --profile --cache-sksl --purge-persistent-cache
该参数可能会删除 SkSL 着色器捕获的较旧的非 SkSL着色器缓存,因此只能在第一次运行时使用 --cache-sksl。
在不同平台上,可以执行以下命令,使用 SkSL 预热功能构建应用程序:
flutter build apk — bundle-sksl-path flutter_01.sksl.json
相关文章:

【Android常见问题(五)】- Flutter项目性能优化
文章目录 知识回顾前言源码分析1. 渲染过程2. 分析工具3. 优化方法合理使用const关键词合理使用组件管理着色器编译垃圾 知识回顾 前言 项目迭代开发一定程度后,性能优化是重中之重,其中包括了包体积,UI 渲染、交互等多个方面。 通过 Flutt…...
JSON转换:实体类和JSONObject互转,List和JSONArray互转(fastjson版)
//1.java对象转化成String String sJSONObject.toJSONString(javaObject.class); //2. java对象转化成Object Object strJSONObject.toJSON(javaObject.class); //3.String类型转json对象 JSONObject jsonObject JSONObject.parseObject(str); //4. String…...
Java单例模式几种代码详解
在软件开发中,单例模式是一种常见的设计模式,它的目的是确保一个类在任何情况下都只有一个实例,同时提供一个全局访问点。在Java中,有几种常见的实现单例模式的方式,下面将逐一进行详细解释。 懒汉式(非线…...

PHP代码审计--理论
提供资料: php 基础 : https://www.runoob.com/php/php-tutorial.html php是什么? PHP 是服务器端脚本语言。 首先在学习PHP前需要对HTML 和CSS有一定的认识 PHP 能做什么? PHP 可以生成动态页面内容PHP 可以创建、打开、读取、写入、关…...

在云服务器上,clone github时报Connection timed outexit code: 128
文章目录 问题解决方案 问题 在执行pip install安装依赖时,需要clone github代码,此时报了Connection timed out&exit code: 128错误,原因是访问超时了,此时需要使用代理 fatal: unable to access https://github.com/hugg…...

小型双轮差速底盘寻迹功能的实现
1. 功能说明 寻迹机器人是一种能够跟踪特定物体或线路的机器人。它们通常具有以下功能和特点: ① 传感器:寻迹机器人配备了用于感知环境的传感器,如摄像头、灰度传感器等。这些传感器可以探测地面上的标记、颜色、纹理或其他特定特征…...

第七篇:k8s集群使用helm3安装Prometheus Operator
安装Prometheus Operator 目前网上主要有两种安装方式,分别为:1. 使用kubectl基于manifest进行安装 2. 基于helm3进行安装。第一种方式比较繁琐,需要手动配置yaml文件,特别是需要配置pvc相关内容时,涉及到的yaml文件太…...

Chrome 75不支持保存成mhtml的解决方法
在Chrome 75之前,可以设置chrome://flags -> save as mhtml来保存网页为mhtml。 升级新版,发现无法另存为/保存网页为MHTML了。 在网上搜索无果后,只得从chromium项目的commits中查找,原来chrome搞了个"Chrome Flag Owner…...

工程监测振弦采集仪应用于岩土工程监测案例
振弦采集仪是一种用于测量地面或岩土中振动参数的仪器,可以对地基、土壤和岩体的性质及其变化进行监测。在岩土工程监测中,振弦传感器被广泛应用于测量土体或岩体的振动情况,以了解地震或其他自然灾害的影响。 以下是一个振弦采集仪应用岩土工…...

配置HDFS单机版,打造数据存储的强大解决方案
目录 简介:步骤:安装java下载安装hadoop配置hadoop-env.sh配置 core-site.xml配置hdfs-site.xml初始化hdfs文件系统启动hdfs服务验证hdfs 结论: 简介: Hadoop分布式文件系统(HDFS)是Hadoop生态系统中的一个…...

U盘删除的文件怎么找回?4个简单方法分享!
“在u盘里不小心删除的文件到底还能不能找回来呀?真的好着急啊!这个u盘对我来说真的很重要,怎么恢复里面的数据呢?请各位大佬帮帮我吧!” 作为一个便捷的存储工具,u盘逐渐获得大众的青睐。在互联网时代&…...

【雕爷学编程】MicroPython动手做(27)——物联网之掌控板小程序2
知识点:什么是掌控板? 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片,支持WiFi和蓝牙双模通信,可作为物联网节点,实现物联网应用。同时掌控板上集成了OLED…...
形参动态内存开辟和柔性数组
//柔性数组 //定义:结构体最后一个成员允许是未知大小的数组 // 优点;在开辟空间时,连续开辟,便于释放空间,不会因多次开辟,导致释放空间出错 // 开辟空间时,节省动态开辟次数,节省空间&am…...

【LLM系列之指令微调】长话短说大模型指令微调的“Prompt”
1 指令微调数据集形式“花样”太多 大家有没有分析过 prompt对模型训练或者推理的影响?之前推理的时候,发现不加训练的时候prompt,直接输入模型性能会变差的,这个倒是可以理解。假如不加prompt直接训练,是不是测试的时…...

MacOS使用brew如何下载Nginx
首先,第一步切换源: 切换 brew.git 仓库地址: cd "$(brew --repo)" git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git 替换 homebrew-core.git 仓库地址: cd "$(brew --repo)/Library/Taps/home…...
linux ftp
使用ftp连接本机进行文件传输 1、下载vsftpd服务器程序 apt install vsftpd 2、使用tcp抓包 tcpdump -nt -i lo port 20 在FTP连接到本地主机(127.0.0.1)时,数据可能通过本地回环接口(loopback interface)传输&…...

你知道HTTP与HTTPS有什么区别吗?
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 目录 一、什么是HTTP? 二、什么是HTTPS? 三、HTTPS 的工作原理 1、客户端发起 HTTPS 请求 2、服务端的配置 3、…...

keil使用printf函数重定串口输出,程序卡在Reset_Handler
最近在做国产芯片GD32F103项目,使用printf()函数重定向USART0串口输出,发现程序没有运行,单步调试发现,程序卡在startup_gd32f10x.s文件的Reset_Handler处,记录一下解决方法。 解决办法: 1、引用头文件#in…...
Redis预热 雪崩 击穿 穿透
redis预热 在Redis中,预热是指在实际的负载之前,提前将数据加载到内存中,以便在请求到来时能够快速响应。预热可以减少冷启动时的延迟,并提高系统的性能。 有几种方法可以进行Redis的预热: 使用持久化机制࿱…...

Shell脚本学习-MySQL单实例和多实例启动脚本
已知MySQL多实例启动命令为: mysqld_safe --defaults-file/data/3306/my.cnf & 停止命令为: mysqladmin -uroot -pchang123 -S /data/3306/mysql.sock shutdown 请完成mysql多实例的启动脚本的编写: 问题分析: 要想写出脚…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...

从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...