Flutter学习(2)

325 阅读11分钟

Flutter总结评估

一、Futter简介

Flutter是Google使用Dart语言开发的移动应用开发框架,使用一套Dart代码就能构建高性能、高保真的iOS和Android应用程序,并且在排版、图标、滚动、点击等方面实现零差异。

如何实现跨平台:Flutter能够在iOS和Android上运行起来,依靠的是一个叫Flutter Engine的虚拟机,Flutter Engine是Flutter应用程序的运行环境,开发人员可以通过Flutter框架和API在内部进行交互。

二、Flutter特点

1、 快速开发:由于Flutter选用了Dart作为其开发语言,Dart既可以是AOT(Ahead Of Time)编译,也可以是JIT(Just In Time)编译,其JIT编译的特性使Flutter在开发阶段可以达到亚秒级有状态热重载,从而大大提升了开发效率。

2、 性能优越:使用自带的高性能渲染引擎(Skia)进行自绘,渲染速度和用户体验堪比原生。

3、 富有表现力的精美UI:Flutter内置众多精美的Material Design和Cupertino(iOS风格)小部件,开发者可快速构建精美的用户界面,以提供更好的用户体验。

三、Flutter系统架构图

如上图所示为Flutter官方给出的系统架构图,可以看出Flutter框架分为三层:Framework层、Engine层和Embedder层。

1、 Framework层:由Dart来实现,包含众多安卓Material风格和iOS Cupertino风格的Widgets小部件,还有渲染、动画、绘图和手势等。Framework包含日常开发所需要的大量API,普通应用开发熟悉这些API的使用基本OK了,不过很多特殊场景的控件需要自己根据实际情况进行自定义。

2、 Engine层:由C/C++实现,是Flutter的核心引擎,主要包括Skia图形引擎、Dart运行时环境Dart VM、Text文本渲染引擎等;

3、 Embedder层:主要处理一些平台相关的操作,如渲染Surface设置、本地插件、打包、线程设置等。

四、Flutter原理

无论是iOS还是安卓都是提供一个平台的View给Flutter层,页面内容渲染交由Flutter层自身来完成,所以其相对React Native等框架性能更好。Flutter中图形渲染流程:

大致流程如下:

GPU的Vsync信号同步到UI线程 UI线程使用Dart来构建抽象的视图结构 视图结构在GPU线程中进行图层合成 合成后的视图数据提供给Skia图形引擎处理成GPU数据 数据再通过OpenGL或Vulkan提供给GPU进行渲染

五、为什么Flutter会选择Dart语言?

1.开发效率高。Dart运行时和编译器支持Flutter的两个关键特性的组合,分别是基于JIT(JIT是just in time,即时编译技术。使用该技术,可以加速java程序的运行速度。 )的快速开发周期和基于AOT(AOT,Ahead Of Time,指运行前编译.)的发布包。基于JIT的快速开发周期:Flutter在开发阶段,采用JIT模式,这样就避免了每次改动都需要进行编译,极大地节省了开发时间。基于AOT的发布包,Flutter在发布时可以通过AOT生成高效的ARM代码,以保证应用性能。而JavaScript则不具备这个能力。

2.高性能。为了实现流畅、高保真的的UI体验,Flutter必须在每个动画帧中都运行大量的代码。这意味着需要一种既能支持高性能,又能保证不丢帧的周期性暂停的语言,而Dart支持AOT,在这一点上比JavaScript更有优势。

3.快速分配内存。Flutter框架使用函数式流,这使得它在很大程度上依赖于底层的内存分配器。

4.类型安全。由于Dart是类型安全的语言,支持静态类型检测,所以可以在编译前就发现一些类型的错误,并排除潜在问题。这对于前端开发者来说更具有吸引力。而JavaScript是一个弱类型语言,这也是为什么在诸多前端社区中,会有众多为JavaScript代码添加静态类型检测的扩展语言和工具。

Flutter Framework使用Dart语言开发,所以App进程中需要一个Dart运行环境(VM),和Android Art一样,Flutter也对Dart源码做了AOT编译,直接将Dart源码编译成了本地字节码,没有了解释执行的过程,提升执行性能。和Java显著不同的是Dart的"线程"(Isolate)是不共享内存的,各自的堆(Heap)和栈(Stack)都是隔离的,并且是各自独立GC的,彼此之间通过消息通道来通信。Dart天然不存在数据竞争和变量状态同步的问题,整个Flutter Framework Widget的渲染过程都运行在一个isolate中。

六、Flutter评测

1、Flutter和其他跨平台框架的性能比较

2、性能方面

1、 CPU使用率: Flutter 对CPU的占用率比iOS、Andriod对CPU的占用率多出1倍。

2、 内存使用率:

iOS:Flutter内存占用率比iOS低。

Andriod:Flutter内存占用率比Andriod高。

3、 包体积:

iOS:Flutter没有优化的时候,比原生大10M左右,这个是因为Flutter.ipa里面App.framework和Flutter.framework包比较大。

Android:Flutter 版的 apk 大小会比 android 原生的多出约 6M 左右,其中核心引擎大约 3.2MB,框架+应用程序代码大约是 1.25MB。必需的 Java 代码 .dex 将近 60k,而 assets 文件里还约有 2.1MB 的 ICU 数据等。

3、开发方面

1、 布局种类多,页面构建速度快:Flutter中拥有30多种预定义的布局widget,常用的有Container、Padding、Center、Flex、Row、Colum、ListView、GridView。

2、 开源框架丰富,包管理方便:分享内容、存储偏好、访问传感器、实现 Firebase 等等。当然,每一个都是同时支持 Android 和 iOS。

Packages会被发布到pub.dartlang.org/,所有已发布的包都支持搜索。

你也可以依赖存储在Git仓库中的包。

3、 支持热重载:Flutter的热重载(hot reload)功能可以帮助您在无需重新启动应用的情况下快速、轻松地进行测试、构建用户界面、添加功能以及修复错误。

4、 开发工具:Android Studio、IntelliJ、VS Code

5、 打包:Android和iOS分别配置证书、包名、应用图标等,可以分别用Android Studio和Xcode打包二进制文件。

6、 发布:将打包好的二进制文件分别上传到安卓商店或苹果商店。

4、框架对比

七、Flutter优缺点

Flutter优点

Flutter的优点非常明显,如果你选择一个跨平台框架,与众多基于html的跨平台框架相比,Flutter绝对是体验最好,性能与构建思路几乎最接近原生开发的框架。

性能强大,流畅

Flutter对比weex和react native相比,性能的强大是有目共睹的。基于dom树渲染原生组件,很难与直接在原生视图上绘图比肩性能,Google作为一个轮子大厂,直接在两个平台上重写了各自的UIKit,对接到平台底层,减少UI层的多层转换,UI性能可以比肩原生,这个优势在滑动和播放动画时尤为明显。

路由设计优秀

Flutter的路由传值非常方便,push一个路由,会返回一个Future对象(也就是Promise对象),使用await或者.then就可以在目标路由pop,回到当前页面时收到返回值。这个反向传值的设计基本是甩了微信小程序一条街了。弹出dialog等一些操作也是使用的路由方法,几乎不用担心出现传值困难

单例模式

Flutter支持单例模式,单例模式的实现也非常简单。单例模式很好的解决了一些问题。相比之下,js的单例则并不是一个真正的单例,或者说不是一个简单的单例,这也是受限于js所运行的环境。单例模式并不总是合理的,容易被滥用。但是在App的初期开发中,往往一个容易实现的单例可以帮助我们快速完成一些逻辑的搭建。

优秀的动画设计

Flutter的动画简单到不可思议,动画对象会根据屏幕刷新率每秒产生很多个(一般是60个)浮点数,只需要将一个组件属性通过补间(Tween)关联到动画对象上,Flutter会确保在每一帧渲染正确的组件,从而形成连贯的动画。这种十分暴力的操作在Flutter上却看不到明显的卡顿,这也是Flutter的一个魔力所在。相比之下其他跨平台框架几乎不能设计动画……往往会遭遇非常严重的性能问题。

UI跨平台稳定

Google直接在两个平台上在底层重写了UIKit,不依赖于Css等外部解释器,几乎不存在UI表达不理想,渲染不正常的情况,可以获得非常稳定的UI表达效果。Css换个浏览器就有不同的表现,基于Css的跨平台框架很难获得稳定的UI表现。

可选静态的语言,语言特性优秀

Dart是一个静态语言,这也是相对于js的一个优势。Dart可以被编译成js,但是看起来更像java。静态语言可以避免错误,获得更多的编辑器提示词,极大的增加可维护性。很多js库也已经用ts重写了,Vue3.0的底层也将全部使用ts编写,静态语言的优势不言而喻。

Flutter缺点

假装跨平台,躲不开原生代码

这是最大的问题,跨平台框架说白了就是UI跨平台,最后还是在原生平台运行,本来两个平台就有天壤之别,一套代码就想吃掉iOS和Android在实际应用之中其实根本就不现实。Flutter具有与原生代码互相调用的能力固然非常科学,但是问题反而显得更加明显——除非对双端很熟悉,开发人员上哪里去知道什么是UIViewController,什么是Activity呢?我要是双端都熟悉,学习Flutter就显得很没有必要。这是一个很矛盾的点,如果有原生开发者,那就没必要搞Flutter了。

组合而不是继承的思路

Flutter提倡“组合”,而不是“继承”。在iOS开发中,我们经常会继承UIView,重写UIView的某个生命周期函数,再添加一些方法和属性,来完成一个自定义的View。但是在Flutter中这些都是不可能的——属性都是final的,例如你继承了了一个Container,你是不能在它的生命周期中修改他的属性的。你始终需要嵌套组合几种Widget,例如Row,Container,ListView等Widget。这种方法非常不符合直觉,初学时很难想明白如何构建一个完整的组件。

Widget的类型难以选择

Flutter的Widget分为StatefulWidget和StatelessWidget两种,一种是带状态的一种是不带状态的,刚开发的时候很难想明白用哪个,因为StatelessWidget也能存值,其实区别就在于框架重构UI的时候会使用State来重构,如果是StatelessWidget,暂时存进去的值就没了。但是问题远不止这么简单,好在只是有点麻烦,并不影响产品性能。

糟糕的UI控件API

虽然google尽可能的让我们通过构造函数定制化Widget,但是也难免有遗漏的。例如,又一次我想修改一个Appbar的高度,居然没有找到关于高度的属性,通过阅读源码发现,高度是写死(const)的。上文已经说过,无法通过生命周期来改变组件属性,自己写Appbar显得非常没必要,毕竟我还是想使用Appbar的各种方便的功能。最后我只能把他的源码全部复制出来,直接修改高度来使用。初学框架,和一些初级开发者是不可能有迅速阅读源码的能力的(作为框架也不应该产生如此问题)。一些定制化的UI的Api设计经常有缺失,好在我已经基本习惯了。除了Appbar这种复杂的组件,自己写一个小组件也并不费事。

糟糕的资源管理设计

这里是最蠢的,Flutter支持动态加载不同分辨率的图片,但是目录设计太鬼畜了。简单的说,Sketch导出的多分辨率资源,几乎不可能直接拖到Flutter里用,极其,极其,麻烦。

八、结论

从 Flutter 的设计理念来看,其整体架构都是具有革命性的,相比于其他架构,它实现了真正意义上的跨平台。它能够让各平台的体验一致,并且让用户体验达到更优。现如今,Flutter 的各种 UI 库和组件都在不断增加,与之相关的各种生态系统和社区也在不断完善,它对新的操作系统的适配性将会越来越强。相信在不久的将来,Flutter 会慢慢成熟起来,成为主流的开发语言之一。