美文网首页
Flutter vs Native

Flutter vs Native

作者: iOS小肖 | 来源:发表于2023-03-07 11:02 被阅读0次

开始之前,我们需要了解一下 flutter 的四种项目结构

application:纯 flutter 应用

plugin:基于原生的 flutter 插件

package:纯 dart 插件

module:原生上集成 flutter 模块

目前我们项目中使用的就是application结构,包含了各种plugin和package插件。如果采用主原生,就是使用module(原生为主、flutter为辅)。

渲染原理

对于原生 Android  而言,是原生代码经过 skia 最后到 GPU 完成渲染绘制,Android 原生系统本身自带了 skia。

对于 Flutter 而言,Dart 代码里的控件经过 skia 最后到 GPU 完成渲染绘制,这里在 Andriod 上使用的系统的 skia ,而在 iOS 上使用的是打包到项目里的 skia。



首先看下用到的线程:

UIThread

      UIThread 是 Platform 创建的子线程,DartVM Root Isolate 所有的 dart 代码都运行在该线程。 阻塞 UIThread 会直接导致 Flutter 应用          卡顿   掉帧。

RasterThread

      RasterThread 它是运行在 CPU 用于处理数据提交给 GPU,它的作用是光栅化。

      C++ Engine 中的光栅化和合成过程运行在该线程。

整个流程会经过以下几个过程:

C++ Engine 触发 Platform 注册 VSync 垂直信号回调,通过 Platform -> C++ Engine -> Dart Framework 触发整个绘制流程

Dart Framework 构建出四棵树,Widget Tree、Element Tree、RenderObject Tree、Layer Tree,布局、记录绘制区域及绘制指令信息生成 flutter::LayerTree,并保存在 Scene 对象用以光栅化,这个过程运行在 UIThread

通过 Flutter 自建引擎 Skia 进行光栅化和合成操作, 将 flutter::LayerTree 转换为 GPU 指令,并发送给 GPU 完成光栅化合成上屏显示操作,这个过程执行在 RasterThread

整个调度过程是生产者消费者模型。

UIThread 负责生产 flutter::Layer Tree,RasterThread 负责消费 flutter::Layer Tree。

这种调度机制可以确保 RasterThread 不至于过载(2 个任务),同时也可以避免 UIThread 不必要的资源消耗。

所以不论在 UIThread 还是在 RasterThread 耗时太久,都可能会导致 Flutter 应用卡顿,因为会导致延迟接受 VSync 信号,导致掉帧。


flutter(主)+ 原生

当我们在 Flutter 中使用UiKitView将一个原生视图嵌入到 Flutter 中时,UiKitView实际上是将该原生视图添加到了 Flutter 引擎的视图树中,并且提供了一个通信通道,让 Flutter 引擎可以和该原生视图进行交互。

原生(主)+  flutter

FlutterViewController的内部原理是通过创建和管理一个FlutterEngine来实现的,它提供了一个简单的接口,可以将Flutter视图无缝地集成到iOS原生应用中

默认情况下,原生的视图渲染和 Flutter Widget 的渲染是互相独立的,不会出现冲突。


测试下flutter版本为3.0.5


iOS: 原生启动内存大小21.3M,flutter启动内存大小41.5M  (release模式,以下测试数据也在该模式)

安卓:原生启动内存大小52M,flutter启动内存大小77 M (profile模式,以下测试数据也在该模式)

包体积对比:

      flutter包大小会比 原生的多出约 6M 左右,其中核心引擎大约 3.2MB,框架+应用程序代码大约是 1.25MB,而 assets 文件里还约有 2.1MB 的 ICU 数据等,单纯从安装包上来说,原生是要优于 flutter 。

测试数据 

启动时长

分析:flutter主要比原生多出 libflutter.so动态库,启动需要链接此库,初始化字体等操作。

首页列表滑动

分析:flutter 在 CPU 和内存的资源占用上会比原生方式多一些,所以单纯的从性能上来说, 原生是肯定要优于 flutter 的,但是从用户体验上来说,两者的滑动同样顺畅无比,几乎感觉不到差别。

动画测试

分析:动画效果上原生更优,内存占比都差不多。

svga测试 

分析:svga内存占比过大,主要是有几个svga游戏结果的分辨率比较大,svga优化只能pag或者vap上进行代替和生成的时候尽量分辨率和帧率上进行控制

秀场拉流展示测试

分析:拉流渲染上,flutter也是原生渲染,然后映射到flutter上插入树中,所以相差不大。

Flutter 图片缓存设计的一些问题

应该说 Flutter 的图片缓存设计还是比较契合 Native UI 的使用场景的,但是对于一些设计比较糟糕的 UI,或者是自动生成的类 Web 的长页面,这样的设计可能会造成一些灾难性的后果。

1. Flutter 解码的时机非常靠前,如果一次性加入大量的 Image Widget 对象,会马上产生相应数量的加载和解码任务,这可能造成系  统较为严重的阻塞,并且部分 Image Widget 实际上可能距离可见区域较远,解码后产生的纹理暂时不会被使用,这造成了内存浪  费;

2. ImageCache 实际上是没有真正封顶的(Live Pool 是无上限的),如果当前的 Widget 树同时包含了大量的 Image Widget,内存    峰值可能会非常夸张,很容易造成 OOM;

3. ImageCache 是在 Framework 层的实现而不是 Engine 层,它的实例由 Widget 层产生,通过 PaintingBinding.instance.imageCache 访问,这意味着每个 FlutterView,每个 Root Isolate 都有一个不同的 ImageCache,如果是混合应用,同时展现多个 FlutterView,不但 ImageCache 的 Live Pool 没法控制,Cache Pool 也会处于叠加的状态,导致内存的峰值会更难以控制;

总结:

通过以上的分析,原生在内存、CPU 资源占用方面要低于 flutter,并且安装包的体积也要小于 flutter,所以,不考虑其他因素,单纯从性能角度来说, 原生肯定是要优于 flutter 的。但 flutter 也有它的优点,比如跨平台的开发、毫秒级的热重载等等,另外跨端开发也逐渐的流行起来,所以,我们在学好原生的基础上,对跨端开发也要抱有积极的心态。

相关文章

网友评论

      本文标题:Flutter vs Native

      本文链接:https://www.haomeiwen.com/subject/ofovldtx.html