2

背景

因为之前没了解过flutter, 本文将从Flutter 技术出现的背景,Flutter的主要思想等方面去了解相关知识技术。

Flutter 技术出现的背景

当前领域 移动开发技术 大概可以分为两种:

  • 原生开发
  • 跨平台技术

跨平台技术 又可以分为以下几种:

  • H5 + 原生(Cordova、Ionic、微信小程序)
  • JavaScript 开发 + 原生渲染 (React Native、Weex)
  • 自绘UI + 原生 (Qt for mobile、Flutter)

以下我们逐一简单介绍一下。

原生开发

原生应用程序是指某一个移动平台(比如iOS或安卓)所特有的应用,使用相应平台支持的开发工具和语言,并直接调用系统提供的SDK API。

比如 Android 原生应用就是指使用 JavaKotlin 语言直接调用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

image.png

很多人都听过React, 毕竟是前端三大框架之一。
其实React Native 是 React 在原生移动应用平台的衍生产物,它是Facebook 于 2015 年 4 月开源的跨平台移动应用开发框架

React 和 React Native 主要的区别在于虚拟 DOM 映射的对象是什么。React中虚拟 DOM 最终会映射为浏览器 DOM 树,而 RN 中虚拟 DOM 会通过 JavaScriptCore 映射为原生控件。

Weex

image.png
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

image.png
Flutter 是 Google 发布的一个用于创建跨平台、高性能移动应用的框架.

2017 年 Google I/O 大会上,Google 首次发布 Flutter。

至今,githun 有 158K Start。github Start 排行 21.

image.png

国内外有非常多基于 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 这个过程,也只会渲染一次。有状态组件的生命周期如下图:

image.png

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、组件销毁


weiweiyi
761 声望111 粉丝

« 上一篇
数字证书
下一篇 »
Mongodb 认识