背景
因为之前没了解过flutter, 本文将从Flutter 技术出现的背景,Flutter的主要思想等方面去了解相关知识技术。
Flutter 技术出现的背景
当前领域 移动开发技术 大概可以分为两种:
- 原生开发
- 跨平台技术
而 跨平台技术 又可以分为以下几种:
- H5 + 原生(Cordova、Ionic、微信小程序)
- JavaScript 开发 + 原生渲染 (React Native、Weex)
- 自绘UI + 原生 (Qt for mobile、Flutter)
以下我们逐一简单介绍一下。
原生开发
原生应用程序是指某一个移动平台(比如iOS或安卓)所特有的应用,使用相应平台支持的开发工具和语言,并直接调用系统提供的SDK API。
比如 Android
原生应用就是指使用 Java
或 Kotlin
语言直接调用Android SDK开发的应用程序;
而 iOS
原生应用就是指通过 Objective-C
或 Swift
语言直接调用iOS SDK开发的应用程序。原生开发有以下主要优势:
优势:
- 可访问手机所有功能(如GPS、摄像头等)、可实现功能齐全;
- 运行速度快、性能高
缺点:
- 移植性比较差,开发周期长,成本高,一款原生的App,Android和IOS都要各自开发,
- 有新版本时,需重新发布版本。
随着互联网发展越来越迅速, 各自开发 Android 和 IOS 不仅面临着开发成本和测试成本昂贵,还面临着更新少量的代码也需要应用版本审核,所以,对应用动态化(不发版也可以更新应用内容)以及降低开发成本的需求就变的迫在眉睫。
跨平台技术
H5 + 原生
这类框架主要原理就是将 App 中需要动态变动的内容通过 HTML5(简称 H5)来实现,通过原生的网页加载控件 WebView (Android)或 WKWebView(iOS)来加载。
WebView (Android):
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = findViewById(R.id.web);
webView.loadUrl("https://www.geeksforgeeks.org");
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient());
}
}
WKWebView(iOS):
class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let myURL = URL(string:"https://www.apple.com")
let myRequest = URLRequest(url: myURL!)
webView.load(myRequest)
}
}
这种方案中,H5 部分是可以随时改变而不用发版,动态化需求能满足;同时,由于 H5 代码只需要一次开发,就能同时在 Android 和 iOS 两个平台运行.
H5代码是运行在 WebView 中,而 WebView 实质上就是一个浏览器内核,其 JavaScript 依然运行在一个权限受限的沙箱中,所以对于大多数系统能力都没有访问权限,如无法访问文件系统、不能使用蓝牙等。
所以框架还需要提供访问系统能力的 API , 然后暴露给 WebView 以供 JavaScript 调用。
例如:WebView JavaScript Bridge, 可提供JavaScript 与原生 API 之间通信的桥梁
优点:
- web技术栈容易上手,生态丰富,开发效率高
缺点:
- 性能体验不佳, 复杂界面不堪重负
JavaScript 开发 + 原生渲染
再来看第二种: JavaScript 开发 + 原生渲染
代表框架有: React Native、Weex、uniapp。
React Native
很多人都听过React, 毕竟是前端三大框架之一。
其实React Native 是 React 在原生移动应用平台的衍生产物,它是Facebook 于 2015 年 4 月开源的跨平台移动应用开发框架
React 和 React Native 主要的区别在于虚拟 DOM 映射的对象是什么。React中虚拟 DOM 最终会映射为浏览器 DOM 树,而 RN 中虚拟 DOM 会通过 JavaScriptCore 映射为原生控件。
Weex
Weex 是阿里巴巴于 2016 年发布的跨平台移动端开发框架,思想及原理和 React Native 类似,底层都是通过原生渲染的。
区别就是,React Native支持 React 语法, 而 Weex 支持Vue。
uniapp
uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。
同样的,uniapp 也是 JavaScript开发 + 原生渲染的方式。可以使用Vue.js的语法和组件开发应用,然后通过UniApp的编译工具将代码转换为微信小程序、H5、以及App所需的原生代码。
小结
JavaScript 开发 + 原生渲染 原理就是通过框架的编译工具来转换成原生控件,以此进行原生渲染。
优点:
- 原生控件渲染,性能相比 H5 提高很多。
- 采用 Web 开发技术栈,开发成本低
- 支持热更新
缺点:
- 依赖于框架的更新
- 复杂的图像或大规模数据处理,JavaScript的性能可能不如原生代码
自绘UI + 原生
自绘UI 和其它方式有什么区别呢?
- 传统方法(非自绘 UI): 如果选择使用每个平台的原生控件,那么在 iOS 上,可以使用 UIKit 来创建按钮和文本框,而在 Android 上,可以使用 Android 的控件。直接使用系统提供的组件,但可能导致在两个平台上的 UI 外观差异,因为两个平台的控件是不一样的。
- 自绘 UI 方法: 需要一个统一的渲染引擎,这个引擎能够在不同平台上绘制应用程序界面。这意味着将不再依赖于系统提供的原生控件,而是通过代码在应用中绘制按钮、文本框等 UI 元素,以确保它们在所有平台上的外观相同。
优点:
- 性能高;由于自绘引擎是直接调用系统API来绘制UI,所以性能和原生控件接近。
- 灵活、组件库易维护、UI外观保真,不会受原生布局系统的限制。
缺点:
- 动态性不足,自绘UI系统一般都会采用 AOT(ahead over time) 模式编译, 不能像JavaScript(JIT)那样动态地编译。
自绘UI 代表作有 QT, 以及今天要介绍的 flutter。
Qt
Qt 是一个1991年由 Qt Company 开发的跨平台 C++ 图形用户界面应用程序开发框架
2014年4月,跨平台集成开发环境 Qt Creator 3.1.0 正式发布,实现了全面支持 iOS、Android。
但是从今天来看,无疑是落寞了。可能是因为 c++ 开发效率低,或者社区不够活跃,相关资料少。
Flutter
Flutter 是 Google 发布的一个用于创建跨平台、高性能移动应用的框架.
2017 年 Google I/O 大会上,Google 首次发布 Flutter。
至今,githun 有 158K Start。github Start 排行 21.
国内外有非常多基于 Flutter 的成功案例, 已在业界得到了广泛的关注和认可。
现在 Google 正在大力推广Flutter,Flutter 的作者中很多人都是来自Chromium团队。
同时开发过程中,flutter 支持 热重载。可以实现毫秒级热重载,并且不会丢失状态。
总结
技术类型 | UI渲染方式 | 性能 | 开发效率 | 动态化 | 框架代表 |
---|---|---|---|---|---|
H5 + 原生 | WebView渲染 | 一般 | 高 | 支持 | Cordova、Ionic |
JavaScript + 原生渲染 | 原生控件渲染 | 好 | 中 | 支持 | RN、Weex、uniapp |
自绘UI + 原生 | 调用系统API渲染 | 好 | Flutter高, Qt低 | 默认不支持 | Qt、Flutter |
Flutter
语言: Dart
Flutter App 采用 Dart 语言开发。
Dart 在 JIT(即时编译)模式下,执行速度与 JavaScript 基本持平。
但是 Dart 支持 AOT,当以 AOT模式运行时,JavaScript 便远远追不上了。
同时 Dart 是类型安全的语言,不像JavaScript 是一个弱类型语言。
官方示例:
import 'dart:math' show Random;
void main() async {
print('Compute π using the Monte Carlo method.');
await for (final estimate in computePi().take(100)) {
print('π ≅ $estimate');
}
}
/// Generates a stream of increasingly accurate estimates of π.
Stream<double> computePi({int batch = 100000}) async* {
var total = 0; // Inferred to be of type int
var count = 0;
while (true) {
final points = generateRandom().take(batch);
final inside = points.where((p) => p.isInsideUnitCircle);
total += batch;
count += inside.length;
final ratio = count / total;
// Area of a circle is A = π⋅r², therefore π = A/r².
// So, when given random points with x ∈ <0,1>,
// y ∈ <0,1>, the ratio of those inside a unit circle
// should approach π / 4. Therefore, the value of π
// should be:
yield ratio * 4;
}
}
Iterable<Point> generateRandom([int? seed]) sync* {
final random = Random(seed);
while (true) {
yield Point(random.nextDouble(), random.nextDouble());
}
}
class Point {
final double x;
final double y;
const Point(this.x, this.y);
bool get isInsideUnitCircle => x * x + y * y <= 1;
}
Dart 语法中很多地方也都借鉴了 Java 和 JavaScript。
可以说,Dart 拥有 JavaScript 灵活的函数式编程,也有像java一样比较不错的垃圾回收机制和类型检查。
上手方面,Flutter 官网就提供了 为 Java 开发人员准备的 Dart 教程.
生命周期
在Flutter中,一切皆是Widget(组件),Widget的功能是“描述一个UI元素的配置数据”.
其中组件又包括无状态组件和有状态组件。
- 无状态组件(StatelessWidget)
- 有状态组件(StatefulWidget)
一个 StatefulWidget 类会对应一个 State 类,State表示与其对应的StatefulWidget要维护的状态。State中的保存的状态信息可以:
- 在widget 构建时可以被同步读取。
- 在widget生命周期中可以被改变,当State被改变时,可以手动调用其setState()方法通知Flutter framework状态发生改变,Flutter framework在收到消息后,会重新调用其build方法重新构建widget树,从而达到更新UI的目的。
Flutter 中说的生命周期,是独指有状态组件的生命周期,对于无状态组件生命周期只有一次 build 这个过程,也只会渲染一次。有状态组件的生命周期如下图:
Flutter 生命周期的整个过程可以分为四个阶段
- 初始化阶段:createState 和 initState
- 组件创建阶段:didChangeDependencies 和 build
- 触发组件 build:didChangeDependencies、setState 或者didUpdateWidget 都会引发的组件重新 build
- 组件销毁阶段:deactivate 和 dispose
createState ,该函数为 StatefulWidget 中创建 State 的方法,当 StatefulWidget 被调用时会立即执行 createState 。
initState ,该函数为 State 初始化调用,因此可以在此期间执行 State 各变量的初始赋值,同时也可以在此期间与服务端交互,获取服务端数据后调用 setState 来设置 State。
didChangeDependencies ,当State对象的依赖发生变化时会被调用.
build ,主要是返回需要渲染的 Widget ,由于 build 会被调用多次,因此在该函数中只能做返回 Widget 相关逻辑,避免因为执行多次导致状态异常。
reassemble, 在 debug 模式下,每次热重载都会调用该函数,因此在 debug 阶段可以在此期间增加一些 debug 代码,来检查代码问题。
didUpdateWidget ,在widget重新构建时,Flutter framework会调用Widget.canUpdate来检测Widget树中同一位置的新旧节点,然后决定是否需要更新.
deactivate ,在组件被移除节点后会被调用,如果该组件被移除节点,然后未被插入到其他节点时,则会继续调用 dispose 永久移除。
dispose ,永久移除组件,并释放组件资源。
总结
Flutter 中 Widget 分为两种:StatelessWidget 和 StatefulWidget
Flutter 生命周期的整个过程可以分为四个阶段:初始化、组件创建、触发组件 build、组件销毁
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。