前言

  有幸负责的模块使用Flutter编写,在三个月的开发过程中,在原有Demo自学基础上又学到了很多,谨以此篇文章做一个Flutter阶段性的学习和总结,以便于往后的学习过程中温故而知新,那么我们正篇开始。

前世今生

  新事物的诞生往往是有一定原因存在的,移动端在这条路上有几个阶段,从Android Native 到 WebView 阶段,为了获得不发版本就可以获得实时动态化的效果,双端使用JSBridge实现了与原生Native底层能力的对接。
  Native容器阶段,主要有React Native为代表,虽然RN依赖于原生渲染,性能好与H5,但是还存在一些问题,比如:JavaScript和原生通信,部分场景存在通讯瓶颈,容易导致卡顿、不同移动平台,空间需要单独维护,原生版本更新后,社区控件更新较慢等问题。

  Flutter阶段,Flutter抛弃了原生系统控件和 Webview,使用自研高性能渲染引擎来绘制Widget,预先(AOT)编译,运行时直接执行Native(arm)代码,Dart代码执行(在UI TaskRunner),图片下载(IO TaskRunner),真正的渲染(GPU TaskRunner),同平台的通信等(Platform TaskRunner即Native概念下的主线程)是互相隔离的。针对布局等的优化:布局计算时单次树走动即可完成;Relayout Boundary机制:如果Child 的size是固定的,那么不会因为Child的Relayout导致Parent ReLayout等布局优化,都让Flutter脱颖而出。

  所以,App引入Flutter,可以有效提高开发效率,避免双端不一致的现象,缩小开发成本。但是Flutter毕竟不是原生,在代码写法上有很多需要注意的地方,文章第三章会主要总结本人在开发和工作中遇到的问题,相比于H5,flutter在动态化方面,支持的并不好。

1 基础知识

1.1 运行模式

  Debug:Debug模式可以在真机和模拟器上同时运行:会进入所有断点,包括debugging信息、debugger aids(比如observatory)和服务扩展。优化了快速develop/run循环,但是没有优化执行速度、二进制大小和部署。命令flutter run就是以这种模式运行的。

  Release : Release模式只能在真机上运行,不能在模拟器上运行:会关闭所有断言和debugging信息,关闭所有debugger工具。优化了快速启动、快速执行和减小包体积。禁用所有的debugging aids和服务扩展。这个模式是为了部署给最终的用户使用。

  Profile:Profile模式只能在真机上运行,不能在模拟器上运行:和Release模式类似,除了启用了服务扩展和tracing,以及一些为了最低限度支持tracing运行的东西(比如可以使用DevTools)。flutter run --profile 可进入该模式。

  Test :headless test模式只能在桌面上运行:和Debug模式不同的是headless的而且你能在桌面运行。命令flutter test就是以这种模式运行的。

1.2 架构设计

  Framework : 使用dart实现,包括Material Design风格的Widget,Cupertino(针对iOS)风格的Widgets,文本/图片/按钮等基础Widgets,渲染,动画,手势等。

  Engine : C++实现,主要包括:Skia,Dart和Text。 Skia是开源的二维图形库,提供了适用于多种软硬件平台的通用API。

  Embedder : 嵌入层,即把Flutter嵌入到各个平台上去,这里做的主要工作包括渲染Surface设置,线程设置,以及插件等。 从这里可以看出,Flutter的平台相关层很低,平台(如iOS)只是提供一个画布,剩余的所有渲染相关的逻辑都在Flutter内部,这就使得它具有了很好的跨端一致性。

1.3 渲染流程

  Widget:Widget树实际上是一个配置树,而真正的UI渲染树是由Element构成;不过,由于Element是通过Widget生成,所以它们之间有对应关系,我们可以宽泛地认为Widget树就是指UI控件树或UI渲染树。

  Element : 一个Widget对象可以对应多个Element对象。这很好理解,根据同一份配置(Widget),可以创建多个实例(Element)。

  从创建到渲染的大体流程是:根据Widget生成Element,然后创建相应的RenderObject并关联到Element.renderObject属性上,最后再通过RenderObject来完成布局排列和绘制。

举个栗子?

  以下例子取自 闲鱼技术博客 闲鱼Flutter复杂业务优化

Container(color: Colors.blue,child: Row(children: [Image.asset('image'),Text('text'),],),
);

  依据上图 来说就是 UI 刷新的时候,Framework 通知 Engine,Engine 会等到下个 Vsync 信号到达的时候,会通知 Framework 进行 animate, build,layout,paint,最后生成 layer 提交给 Engine。Engine 会把 layer 进行组合,生成纹理,最后通过 Open Gl 接口提交数据给 GPU, GPU 经过处理后在显示器上面显示

  在基础能力和业务开发完成后,性能优化和代码检查也是非常重要的,所以后边的文章主要围绕 性能检测和优化 等细节的总结。

3 性能检测工具

结合 Flutter 性能分析 链接 和Flutter 性能视图 等官方文档,整合调试工具说明,并添加自我理解

3.1 Performance Overlay

  开启方式比较多,通过 DevTools TimeLines 或者 run Flutter Inspector 都可以进入

  点击show CPU GPU 图后

● 竖轴表示耗时,沿竖轴的黑线是时间线 (间隔单位为 16ms)
● 横轴则表示帧,垂直的绿色条代表的是当前帧 (如果为红色则代表处理耗时点)
● 上图显示GPU线程消耗的时间 (帧为红色:Widget太多 场景复杂 渲染耗时)
● 下图显示UI线程消耗的时间 (帧为红色:Dart代码有问题 查看build中是否做太多耗时操作)

也可以在代码中开启 PerformanceOverlay 控件

@overrideWidget build(BuildContext context) {Widget app = MaterialApp(// true 展示PerformanceOverlayshowPerformanceOverlay: showPerformanceOverlay,title: 'appname',theme: ThemeData(appBarTheme: AppBarTheme(brightness: Brightness.light),textTheme: textTheme),home: _buildHome(context),builder: (_, widget) {return MediaQuery(data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),child: widget);},);return WillPopScope(child: app,onWillPop: dealWillPop,);}

  showPerformanceOverlay 为MaterialApp自带属性,如果没有使用MaterialApp,可以在代码中通过PerformanceOverlay.allEnabled(checkerboardOffscreenLayers: true); 开启

3.2 DevTools TimeLine

  使用 DevTools 可以在Performance Overlay大粒度卡顿范围内深度挖掘
由于Observatory和DevTools功能类似,且正逐渐被DevTools替代,这里主要罗列DevTools的使用方式。

● 顶部部分列表类似于PerformanceOverlay ,深色代表GPU耗时,浅红色代表UI层耗时(图层过多)
● 中间部分为帧事件图表,分位 UI 和 GPU两部分组成
● 底部部分为CPU图表,主要有三种不同呈现方式来展示CPU调用堆栈信息

  我们也可以通过添加一些系统api ,更方便我们定位事件图表具体执行位置
debugProfileBuildsEnabled - 向 Timeline 事件中添加 build 信息
debugProfilePaintsEnabled - 向 timeline 事件中添加 paint 信息
debugPrintRebuildDirtyWidgets - 记录每帧重建的 widget

  和Android Profiler 类似,帧事件横轴代表事件顺序,纵轴 代表方法调用堆栈,我们可以通过事件宽度来判断那些事件是比较耗时的。

3.3 Widget rebuild stats

  Android Studio 中 View > Tool Windows > Flutter Performance 打开性能工具窗口,在 Widget rebuild stats 中勾选 Track widget rebuilds 来查看 widget 的重建信息。重建信息包括 Widget 名字、源码位置、上一帧中重建次数、当前页面中重建次数。此外,Widget 名字前面还会显示一个小图标。
● 黄色旋转圆圈 - 重建次数过多
● 灰色圆圈 - 未重建
● 灰色旋转圆圈 其他情况

4 性能优化

  上一章,对于检测工具大概的总结了使用方式和看法,下边我们就根据工具,来定位界面的问题,并总结出我的优化方式。

4.1 列表优化

  在商品2.0中列表占比是比较多得,首页列表的交互逻辑更为复杂,如何让用户用起来如丝般顺滑,需要进行一些性能的打磨。

问题:
界面滑动的时候 会有轻微掉帧现象,检测 fps长期飘红(小于 60fps)

(图一 Flutter Performance 截图)


(图二 DevTools Fps ui GPU 截图)

方案:

  更换PowerScrollView 后列表 滑动FPS和部分DevTools截图
PowerScrollView :概念链接

PowerScrollView 优化点:

  1. 针对PowerDataManager 数据可以做到增量更新。
  2. 添加缓存数组,监控_childElements方法来对element 进行缓存,当滚动超出 viewport 的显示以及预加载范围或者数据源发生变化,会通过调用 collectGarbage 方法回收不需要的 elements)
  3. cell 层面引入了 placeholder 的机制,快速滑动场景优化build工作量
  4. 更多样的瀑布流 、列表样式可供选择等等优化

引入后效果,


(图一 Flutter performance 截图)

图中红色部分主要处于手指第一次按下,并且执行了顶部商品工具栏动画的原因

(图二 DevTools FPS UI GPU 截图)

  上图可以看到 gpu占比较多,列表滑动起始部分还是有卡顿部分,主要是由于首页商品工具栏过度动画 和 首页复杂的UI展示引起的,后续可以通过

4.2 优化 ClipPath 和 ClipRPath

  在刚开始调试初期,使用 Timeline 查看渲染线程性能消耗,可以发现有多个 ClipRectLayer 和 ClipRRectLayer过程,对比商品首页界面后,猜测是在Flutter壳工程中使用自带Image展示图片的时候,对于大图没有进行裁剪显示,部分圆角Widget也需要优化,同时修复 radius 为0也会设置 ClipRRect 的问题。

4.3 常用优化方法

  1. 尽量将setState放在叶子节点,好处是build时影响范围极小,局部刷新
  2. 使用ListView.builder()而不是直接使用ListView()来构建列表 (官方推荐)
  3. 对于频繁更新的控件,使用RepaintBoundary隔离,让其拥有一个独立的paint区域
  4. 使用const来修饰永远不需要变更的控件,如果宽高固定,推荐固定宽高,避免重复计算
  5. 按需使用StateLessWidget,并非全部用StateFulWidget
  6. 使用Visibility控件,避免布局树频繁切换
  7. 针对于使用Fish-redux,state 对象中的视图数据真正发生变化的时候,新建 state 对象
  8. 使用图片替换半透明效果,减少saveLayer 或者clipPath 的使用。

最后

不知不觉已经写到了最后,对于Flutter的学习和使用,一直都在路上,文章中不免有些纰漏,还望大佬们海涵并指出,后续会继续深耕Flutter 动态化方案和Flutter性能优化,继续努力学习,继续满血冲冲冲!

Flutter 学习与性能优化总结相关推荐

  1. 如何学习Linux性能优化?

    如何学习Linux性能优化? 你是否也曾跟我一样,看了很多书.学了很多 Linux 性能工具,但在面对 Linux 性能问题时,还是束手无策?实际上,性能分析和优化始终是大多数软件工程师的一个痛点.但 ...

  2. 深入云原生 AI:基于 Alluxio 数据缓存的大规模深度学习训练性能优化

    作者 | 车漾(阿里云高级技术专家).顾荣(南京大学 副研究员) 导读:Alluxio 项目诞生于 UC Berkeley AMP 实验室,自开源以来经过 7 年的不断开发迭代,支撑大数据处理场景的数 ...

  3. 工程之道,解读业界最佳的深度学习推理性能优化方案

    本文转载自旷视研究院 MegEngine「训练推理一体化」的独特范式,通过静态图优化保证模型精度与训练时一致,无缝导入推理侧,再借助工业验证的高效卷积优化技术,打造深度学习推理侧极致加速方案,实现当前 ...

  4. 深度学习推理性能优化,一个越来越重要的话题

    向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程   公众号:datayx 为什么我们开始关注和重视推理性能的优化. 天时 深度学习的上半场主题是自证, 数据科学家们设计 ...

  5. 推荐学习-Linux性能优化实战

    学习交流加(可免费帮忙下载CSDN资源): 个人微信: liu1126137994 学习交流资源分享qq群1(已满): 962535112 学习交流资源分享qq群2: 780902027 推荐一个学习 ...

  6. 2019 下半年 Flutter 实现的性能优化 | 英雄榜

    作者 / Yuqian Li & Shams Zakhour 高性能是 Flutter 的关键特性之一.我们希望通过本文着重分享在 2019 年下半年由整个 Flutter 社群实现的性能优化 ...

  7. 阿里云原生实践:基于 Alluxio 数据缓存的大规模深度学习训练性能优化

    导读:Alluxio 项目诞生于 UC Berkeley AMP 实验室,自开源以来经过 7年的不断开发迭代,支撑大数据处理场景的数据统一管理和高效缓存功能日趋成熟.然而,随着云原生人工智能(Clou ...

  8. 学习Linux性能优化实战-1

    文章目录 前言 平均负载 命令 进程调度 命令 相关文件 CPU使用率 perf 软中断 测试工具 前言 最近在极客时间上面发现了倪鹏飞老师的Linux性能优化实战,自己感觉讲得很好,有兴趣的朋友可以 ...

  9. webpack学习:性能优化

    本文内容如下 性能优化相关内容 如果你都有了答案,可以忽略本文章,或去webpack学习导图寻找更多答案 性能优化两大方面 一,开发环境性能优化 优化: 构建速度,代码调试 HMR热模块更新(代码调试 ...

  10. Java学习之性能优化常用方法分享

    Java是面向对象编程语言,具有功能强大.简单易用两大特征.很多人表示Java运行速度慢,有严重的性能问题,其实这与Java无关,而是涉及到Java应用的性能优化.接下来我就给大家分享Java性能优化 ...

最新文章

  1. JavaScript学习记录 (三) 函数和对象
  2. 应届毕业生没有工作经验,怎么才能找到合适的工作?
  3. 升级IOS8游戏上传自定义头像功能失效的问题
  4. Angular的property binding一个例子
  5. kafka java编程demo_Kafka简单客户端编程实例
  6. 嵌入式linux mongodb,小白在Ubuntu安装mongoDB与mongo-c-driver
  7. C/C++轻松实现文件下载
  8. 2020 年 Go 语言盘点:Go 的前进步伐不可阻挡
  9. AsynTask用法
  10. HTML的Demo实例
  11. 文本特征提取方法研究
  12. TTL反相器 电路分析
  13. nexus上传jar总是读条而上传不成功的问题
  14. ffmeg将多段视频合成一个视频
  15. 输出青蛙跳台所有路径
  16. 红米5双清_红米手机双清方法
  17. Linux查看磁盘使用情况
  18. MyBatis入门学习(二)
  19. html页面转盘如何实现,html5制作转盘的详解及实例
  20. 手机怎么在线拍照翻译英语?只要几个步骤轻松解决

热门文章

  1. 隋政军---将木屋烧烤打造成中国领先的烧烤品牌
  2. Android,java敏感词,QQ,微信自动过滤组件
  3. gmoj 6841. 【2020.11.5提高组模拟】淘淘蓝蓝之树林
  4. 罗技无线键盘Windows和Ubuntu下锁定Fn键方法
  5. 阿里云服务器常用配置价格表
  6. GAMES101-现代计算机图形学入门-闫令琪——Lecture 18 Advanced Topics in Rendering
  7. 成倍提升ORM系统SQL性能的一个方法
  8. (一)Activiti 数据库25张表——流程历史记录表20(ACT_HI_DETAIL)
  9. 如何使用pr制作视频人物运动残影特效
  10. 基于RTMP的视频采集上报播放预警方案设计与实现