大神一篇文,胜读十年书!Flutter-与-React-Native-的对比分析(2)

本文探讨了Dart与JS的区别,强调了Dart的伪动态强类型特性,以及ReactNative和Flutter在界面开发、状态管理、原生控件和插件开发等方面的差异,同时分析了两者在性能和编译产物方面的特点。
摘要由CSDN通过智能技术生成

var a = 1;

void doSomeThing() async {
var result = await xxxx();
doAsync().then((res) {
print(‘ffff’);
});
}
_loadUserInfo() async* {
print(“**********************”);
yield UpdateUserAction(res.data);
}

但是它们之间的差异性也很多,而最大的区别就是: JS 是动态语言,而 Dart 是伪动态语言的强类型语言。

如下代码中,在 Dart 中可以直接声明 name 为 String 类型,同时 otherName 虽然是通过 var 语法糖声明,但在赋值时其实会通过自推导出类型 ,而 dynamic 声明的才是真的动态变量,在运行时才检测类型。

// Dart

String name = ‘dart’;
var otherName = ‘Dart’;
dynamic dynamicName = ‘dynamic Dart’;

如下图代码最能体现这个差异,在下图例子中:

  • var i 在全局中未声明类型时,会被指定为 dymanic ,从而导致在 init() 方法中编译时不会判断类型,这和 JS 内的现象会一致。

  • 如果将 var i = ""; 定义在 init() 方法内,这时候 i 已经是强类型 String了 ,所以编译器会在 i++报错,但是这个写法在 JS 动态语言里,默认编译时是不会报错的。

动态语言和非动态语言都有各种的优缺点,比如 JS 开发便捷度明显会高于 Dart ,而 Dart 在类型安全和重构代码等方面又会比 JS 更稳健。

3.2、界面开发

React Native 在界面开发上延续了 React 的开发风格,支持 scss/sass 、样式代码分离、在 0.59 版本开始支持 React Hook 函数式编程 等等,而不同 React 之处就是更换标签名,并且样式和属性支持因为平台兼容做了删减。

如下图所示,是一个普通 React Native 组件常见实现方式,继承 Component 类,通过 props 传递参数,然后在 render 方法中返回需要的布局,布局中每个控件通过 style 设置样式 等等,这对于前端开发者基本上没有太大的学习成本。

如下所示,如果再配合 React Hooks 的加持,函数式的开发无疑让整个代码结构更为简洁。

Flutter 最大的特点在于: Flutter 是一套平台无关的 UI 框架,在 Flutter 宇宙中万物皆 Widget

如下图所示,Flutter 开发中一般是通过继承 无状态 StatelessWidget 控件或者 有状态 StatefulWidget 控件 来实现页面,然后在对应的 Widget build(BuildContext context) 方法内实现布局,利用不同 Widget 的 child / children 去做嵌套,通过控件的构造方法传递参数,最后对布局里的每个控件设置样式等。

而对于 Flutter 控件开发,目前最多的吐槽就是 控件嵌套和样式代码不分离 ,样式代码分离这个问题我就暂不评价,这个真要实际开发才能更有体会,而关于嵌套这里可以做一些 “洗白” :

Flutter 中把一切皆为 Widget 贯彻得很彻底,所以 Widget 的颗粒度控制得很细 ,如 Padding 、Center 都会是一个单独的 Widget,甚至状态共享都是通过 InheritedWidget 共享 Widget 去实现的,而这也是被吐槽的代码嵌套样式难看的原因。

事实上正是因为颗粒度细,所以你才可以通过不同的 Widget , 自由组合出多种业务模版, 比如 Flutter 中常用的 Container ,它就是官方帮你组合好的模板之一, Container 内部其实是由 Align、 ConstrainedBox 、DecoratedBox 、Padding 、Transform 等控件组合而成 ,所以嵌套深度等问题完全是可以人为控制,甚至可以在帧率和绘制上做到更细致的控制。

当然,官方也在不断地改进优化编写和可视化的体验,如下图所示,从目前官方放出的消息上看,未来这个问题也会被进一步改善。

最后总结一下,抛开上面的开发风格,React Native 在 UI 开发上最大的特点就是平台相关,而 Flutter 则是平台无关,比如下拉刷新,在 React Native 中, <RefreshControl> 会自带平台的不同下拉刷新效果,而在 Flutter 中,如果需要平台不同下拉刷新效果,那么你需要分别使用 RefreshIndicator 和 CupertinoSliverRefreshControl 做显示,不然多端都会呈现出一致的效果。

3.3、状态管理

前面说过, Flutter 在很多方面都借鉴了 React Native ,所以在状态管理方面也极具“即视感”,比如都是调用 setState 的方式去更新,同时操作都不是立即生效的 ,当然它们也有着差异的地方,如下代码所示:

  • 正常情况下 React Native 需要在 Component 内初始化一个 this.state 变量,然后通过 this.state.name 访问 。
  • Flutter 继承 StatefulWidget ,然后在其的 State 对象内通过变量直接访问和 setState 触发更新。

/// JS

this.state = {
name: “”
};

···

this.setState({
name: “loading”
});

···

this.state.name

/// Dart

var name = “”;

setState(() {
name = “loading”;
});

···

Text(name)

复制代码

当然它们两者的内部实现也有着很大差异,比如 React Native 受 React diff 等影响,而 Flutter 受 isRepaintBoundary 、markNeedsBuild 等影响。

而在第三方状态管理上,两者之间有着极高的相似度,如早期在 Flutter 平台就涌现了很多前端的状态管理框架如:flutter_redux 、fish_redux 、 dva_flutter 、flutter_mobx 等等,它们的设计思路都极具 React 特色。

同时 Flutter 官方也提供了 scoped_model 、provider 等具备 Flutter 特色的状态管理。

所以在状态管理上 React Native 和 Flutter 是十分相近的,甚至是在跟着 React 走。

3.4、原生控件

在跨平台开发中,就不得不说到接入原有平台的支持,比如 在 Android 平台上接入 x5 浏览器 、接入视频播放框架、接入 Lottie 动画框架等等。

这一需求 React Native 先天就支持,甚至在社区就已经提供了类似 lottie-react-native 的项目。 因为 React Native 整个渲染过程都在原生层中完成,所以接入原有平台控件并不会是难事 ,同时因为发展多年,虽然各类第三方库质量参差不齐,但是数量上的优势还是很明显的。

而 Flutter 在就明显趋于弱势,甚至官方在开始的时候,连 WebView 都不支持,这其实涉及到 Flutter 的实现原理问题。

因为 Flutter 的整体渲染脱离了原生层面,直接和 GPU 交互,导致了原生的控件无法直接插入其中 ,而在视频播放实现上, Flutter 提供了外界纹理的设计去实现,但是这个过程需要的数据转换,很明显的限制了它的通用性, 所以在后续版本中 Flutter 提供了 PlatformView 的模式来实现集成。

以 Android 为例子,在原生层 Flutter 通过 Presentation 副屏显示的原理,利用 VirtualDisplay 的方式,让 Android 控件在内存中绘制到 Surface 层。 VirtualDisplay 绘制在 Surface 的 textureId ,之后会通知到 Dart 层,在 Dart 层利用 AndroidView 定义好的 Widget 并带上 textureId ,那么 Engine 在渲染时,就会在内存中将 textureId 对应的数据渲染到 AndroidView 上。

PlatformView 的设计必定导致了性能上的缺陷,最大的体现就是内存占用的上涨,同时也引导了诸如键盘无法弹出#19718和黑屏等问题,甚至于在 Android 上的性能还可能不如外界纹理。

所以目前为止, Flutter 原生控件的接入上是仍不如 React Native 稳定。

四、 插件开发

React Native 和 Flutter 都是支持插件开发,不同在于 React Native 开发的是 npm 插件,而 Flutter 开发的是 pub 插件。

React Native 使用 npm 插件的好处就是:可以使用丰富的 npm 插件生态,同时减少前端开发者的学习成本。

但是使用 npm 的问题就是太容易躺坑,因为 npm 包依赖的复杂度和深度所惑,以至于你都可能不知道 npm 究竟装了什么东西,抛开安全问题,这里最直观的感受就是 :“为什么别人跑得起来,而我的跑不起来?” 同时每个项目都独立一个 node_module ,对于硬盘空间较小的 Mac 用户略显心酸。

Flutter 的 pub 插件默认统一管理在 pub 上,类似于 npm 同样支持 git 链接安装,而 flutter packages get 文件一般保存在电脑的统一位置,多个项目都引用着同一份插件。

  • win 一般是在 C:\Users\xxxxx\AppData\Roaming\Pub\Cache 路径下
  • mac 目录在 ~/.pub-cache

如果找不到插件目录,也可以通过查看 .flutter-plugins 文件,或如下图方式打开插件目录。

最后说一下 Flutter 和 React Native 插件,在带有原生代码时不同的处理方法:

  • React Native 在安装完带有原生代码的插件后,需要执行 react-native link 脚本去引入支持,具体如 Android 会在 setting.gradle 、 build.gradle 、MainApplication.java 等地方进行侵入性修改而达到引用。

  • Flutter 则是通过 .flutter-plugins 文件,保存了带有原生代码的插件 key-value 路径 ,之后 Flutter 的脚本会通过读取的方式,动态将原生代码引入,最后通过生成 GeneratedPluginRegistrant.java 这个忽略文件完成导入,这个过程开发者基本是无感的。

所以在插件这一块的体验, Flutter 是略微优于 React Native 的。

五、 编译和产物

React Native 编译后的文件主要是 bundle 文件,在 Android 中是 index.android.bunlde 文件,而在 IOS 下是 main.jsbundle 。

Flutter 编译后的产物在 Android 主要是 :

  • isolate_snapshot_instr 应用程序指令段
  • isolate_snapshot_data应用程序数据段
  • vm_snapshot_data 虚拟机数据段
  • vm_snapshot_instr 虚拟机指令段等产物

⚠️注意,1.7.8 之后的版本,Android 下的 Flutter 已经编译为纯 so 文件。

在 IOS 主要是 App.framework ,其内部也包含了 kDartVmSnapshotData 、kDartVmSnapshotInstructions 、 kDartIsolateSnapshotData 、kDartIsolateSnapshotInstructions 四个部分。

接着看完整结果,如下图所示,是空项目下 和 GSY 实际项目下, React Native 和 Flutter 的 Release 包大小对比。

可以看出在 React Native 同等条件下, Android 比 IOS 大很多 ,这是因为 IOS 自带了 JSCore ,而 Android 需要各类动态 so 内置支持,而且这里 Android 的动态库 so 是经过了 ndk 过滤后的大小,不然还会更大。

Flutter 和 React Native 则是相反,因为 Android 自带了 skia ,所以比没有自带 skia 的 IOS 会小得多。

以上的特点在 GSY 项目中的 Release 包也呈同样状态。

值得注意的是,Google Play 最近发布了 《8月不支持 64 位,App 将无法上架 Google Play!》 的通知 ,同时也表示将停止 Android Studio 32 位的维护,而 arm64-v8a 格式的支持,React Native 需要在 0.59 以后的版本才支持。

至于 Flutter ,在打包时通过指定 flutter build apk --release --target-platform android-arm64 即可。

六、性能

说到性能,这是一个大家都比较关心的概念,但是有一点需要注意,抛开场景说性能显然是不合适的,因为性能和代码质量与复杂度是有一定联系的。

先说理论性能,在理论上 Flutter 的设计性能是强于 React Native ,这是框架设计的理念导致的,Flutter 在少了 OEM Widget ,直接与 CPU / GPU 交互的特性,决定了它先天性能的优势。

这里注意不要用模拟器测试性能,特别是IOS模拟器做性能测试,因为 Flutter 在 IOS模拟器中纯 CPU ,而实际设备会是 GPU 硬件加速,同时只在 Release 下对比性能。

代码的实现方式不同,也可能会导致性能的损失,比如 Flutter 中 skia 在绘制时,saveLayer 是比较消耗性能的,比如 透明合成、clipRRect 等等,都会可能需要 saveLayer 的调用, 而 saveLayer 会清空GPU绘制的缓存,导致性能上的损耗,从而导致开发过程中如果掉帧严重。

最后如下图所示,是去年闲鱼用 GSY 项目做测试对比的数据,原文在《流言终结者- Flutter和RN谁才是更好的跨端开发方案?》 ,可以看出在去年的时候, Flutter的整体帧率和绘制就有了明显的优势。

额外补充一点,JS 和 Dart 都是单线程应用,利用了协程的概念实现异步效果,而在 Flutter 中 Dart 支持的 isolate ,却是属于完完全全的异步线程处理,可以通过 Port 快捷地进行异步交互,这大大拓展了 Flutter 在 Dart 层面的性能优势。

七、发展未来

之前一篇 《为什么 Airbnb 放弃了 React Native?》 文章,让众多不明所以的吃瓜群众以为 React Native 已经被放弃,之后官方发布的 《Facebook 正在重构 React Native,将重写大量底层》 公示,又再一次稳定了军心。

同时 React Native 在 0.59 版本开始支持 React Hook 等特性,并将原本平台的特性控件从 React Native 内部剥离到社区,这样控件的单独升级维护可以更加便捷,同时让 React Native 与 React 之间的界限越发模糊。

Flutter UI 平台的无关能力,让 Flutter 在跨平台的拓展上更为迅速,尽管 React Native 也有 Web 和 PC 等第三方实现拓展支持,但是由于平台关联性太强,这些年发展较为缓慢, 而 Flutter 则是短短时间又宣布 Web 支持,甚至拓展到 PC 和嵌入式设备当中。

这里面对于 Flutter For Web 相信是大家最为关心的话题, 如下图所示,在 Flutter 的设计逻辑下,开发 Flutter Web 的过程中,你甚至感知不出来你在开发的是 Web 应用。

Flutter Web 保留了 大量原本已有的移动端逻辑,只是在 Engine 层利用 Dart2Js 的能力实现了差异化, 不过现阶段而言,Flutter Web 仍处在技术预览阶段,不建议在生产环境中使用 。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

总结

开发是面向对象。我们找工作应该更多是面向面试。哪怕进大厂真的只是去宁螺丝,但你要进去得先学会面试的时候造飞机不是么?

作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

960页全网最全Android开发笔记

资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

-P7e3V5cH-1712391612649)]

资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值