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”
});
···
/// 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移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
总结
开发是面向对象。我们找工作应该更多是面向面试。哪怕进大厂真的只是去宁螺丝,但你要进去得先学会面试的时候造飞机不是么?
作者13年java转Android开发,在小厂待过,也去过华为,OPPO等,去年四月份进了阿里一直到现在。等大厂待过也面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
-P7e3V5cH-1712391612649)]
资料太多,全部展示会影响篇幅,暂时就先列举这些部分截图
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。