AICon 深圳站 Keynote 嘉宾官宣!共探AI价值转化的实践路径 了解详情
写点什么

写给前端工程师的 Flutter 教程(上)

  • 2019-10-31
  • 本文字数:3521 字

    阅读完需:约 12 分钟

写给前端工程师的 Flutter 教程(上)

最爱折腾的就是前端工程师了,从 jQuery 折腾到 AngularJs,再折腾到 Vue、React。最爱跨屏的也是前端工程师,从 phonegap,折腾到 React Native,这不又折腾到了 Flutter。

图啥?低成本地为用户带来更优秀的用户体验。目前来说 Flutter 可能是其中最优秀的一种方案了。

Flutter 是什么?

Flutter 是由原 Google Chrome 团队成员,利用 Chrome 2D 渲染引擎,然后精简 CSS 布局演变而来。



Flutter 架构


或者更详细的版本:



  • Flutter 在各个原生的平台中,使用自己的 C++的引擎渲染界面,没有使用 webview,也不像 RN、NativeScript 一样使用系统的组件。

  • 简单来说平台只是给 Flutter 提供一个画布。

  • 界面使用 Dart 语言开发,貌似唯一支持 JIT,和 AOT 模式的强类型语言。

  • 写法非常的现代,声明式,组件化,Composition > inheritance,响应式……就是现在前端流行的这一套 :smile:

  • 一套代码搞定所有平台。

Flutter 为什么快?Flutter 相比 RN 的优势在哪里?

从架构中实际上已经能看出 Flutter 为什么快,至少相比之前的当红炸子鸡 React Native 快的原因了。


  • Skia 引擎,Chrome, Chrome OS,Android,Firefox,Firefox OS 都以此作为渲染引擎。

  • Dart 语言可以 AOT 编译成 ARM Code,让布局以及业务代码运行的最快,而且 Dart 的 GC 针对 Flutter 频繁销毁创建 Widget 做了专门的优化。

  • CSS 的子集 Flex like 的布局方式,保留强大表现能力的同时,也保留了性能。

  • Flutter 业务书写的 Widget 在渲染之前 diff 转化成 Render Object,对,就像 React 中的 Virtual DOM,以此来确保开发体验和性能。


而相比 React Native:


  • RN 使用 JavaScript 来运行业务代码,然后 JS Bridge 的方式调用平台相关组件,性能比有损失,甚至平台不同 js 引擎都不一样。

  • RN 使用平台组件,行为一致性会有打折,或者说,开发者需要处理更多平台相关的问题。


而具体两者的性能测试,可以看这里,结论是 Flutter,在 CPU,FPS,内存稳定上均优于 ReactNative。

Dart 语言

在开始 Flutter 之前,我们需要先了解下 Dart 语言。Dart 是由 Google 开发,最初是想作为 JavaScript 替代语言,但是失败沉寂之后,作为 Flutter 独有开发语言又焕发了第二春。


实际上即使到了 2.0,Dart 语法和 JavaScriptFlutter 非常的相像。单线程,Event Loop……



Dart Event Loop 模型


当然作为一篇写给前端工程师的教程,我在这里只想写写 JavaScript 中暂时没有的,Dart 中更为省心,也更“甜”的东西。


  • 不会飘的 this

  • 强类型,当然前端现在有了 TypeScript :grimacing:

  • 强大方便的操作符号:

  • ?. 方便安全的 foo?.bar 取值,如果 foo 为 null,那么取值为 null

  • ?? condition ? expr1 : expr2 可以简写为 expr1 ?? expr2

  • =和其他符号的组合: *=、~/=、&=、|= ……

  • 级联操作符(Cascade notation …)


// 想想这样省了多少变量声明querySelect('#button') ..text ="Confirm" ..classes.add('important') ..onClick.listen((e) => window.alert('Confirmed'))
复制代码


甚至可以重写操作符


class Vector {  final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y); Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
// Operator == and hashCode not shown. For details, see note below. // ···}
void main() { final v = Vector(2, 3); final w = Vector(2, 2);
assert(v + w == Vector(4, 5)); assert(v - w == Vector(0, 1));}
复制代码


注:重写==,也需要重写 Object hashCodegetter


class Person {  final String firstName, lastName;
Person(this.firstName, this.lastName);
// Override hashCode using strategy from Effective Java, // Chapter 11. @override int get hashCode { int result = 17; result = 37 * result + firstName.hashCode; result = 37 * result + lastName.hashCode; return result; }
// You should generally implement operator == if you // override hashCode. @override bool operator ==(dynamic other) { if (other is! Person) return false; Person person = other; return (person.firstName == firstName && person.lastName == lastName); }}
void main() { var p1 = Person('Bob', 'Smith'); var p2 = Person('Bob', 'Smith'); var p3 = 'not a person'; assert(p1.hashCode == p2.hashCode); assert(p1 == p2); assert(p1 != p3);}
复制代码


这点在 diff 对象的时候尤其有用。

1. lsolate

Dart 运行在独立隔离的 iSolate 中就类似 JavaScript 一样,单线程事件驱动,但是 Dart 也开放了创建其他 isolate,充分利用 CPU 的多和能力。


loadData() async {   // 通过spawn新建一个isolate,并绑定静态方法   ReceivePort receivePort =ReceivePort();   await Isolate.spawn(dataLoader, receivePort.sendPort);
// 获取新isolate的监听port SendPort sendPort = await receivePort.first; // 调用sendReceive自定义方法 List dataList = await sendReceive(sendPort, 'https://hicc.me/posts'); print('dataList $dataList');}
// isolate的绑定方法static dataLoader(SendPort sendPort) async{ // 创建监听port,并将sendPort传给外界用来调用 ReceivePort receivePort =ReceivePort(); sendPort.send(receivePort.sendPort);
// 监听外界调用 await for (var msg in receivePort) { String requestURL =msg[0]; SendPort callbackPort =msg[1];
Client client = Client(); Response response = await client.get(requestURL); List dataList = json.decode(response.body); // 回调返回值给调用者 callbackPort.send(dataList); }}
// 创建自己的监听port,并且向新isolate发送消息Future sendReceive(SendPort sendPort, String url) { ReceivePort receivePort =ReceivePort(); sendPort.send([url, receivePort.sendPort]); // 接收到返回值,返回给调用者 return receivePort.first;}
复制代码


当然 Flutter 中封装了 compute,可以方便的使用,譬如在其它 isolate 中解析大的 json。

2. Dart UI as Code

在这里单独提出来的意义在于,从 React 开始,到 Flutter,到最近的 Apple SwiftUI,Android Jetpack Compose 声明式组件写法越发流行,Web 前端使用 JSX 来让开发者更方便的书写,而 Flutter,SwiftUI 则直接从优化语言本身着手。

3. 函数类的命名参数

void test({@required int age,String name}) {  print(name);  print(age);}// 解决函数调用时候,参数不明确的问题test(name:"hicc",age: 30)
// 这样对于组件的使用尤为方便class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Container(), floatingActionButton:FloatingActionButton() ); }}
复制代码


大杀器:Collection If 和 Collection For


// collection IfWidget build(BuildContext context) {  return Row(    children: [      IconButton(icon: Icon(Icons.menu)),      Expanded(child: title),      if (!isAndroid)        IconButton(icon: Icon(Icons.search)),    ],  );}
复制代码


// Collect Forvar command = [  engineDartPath,  frontendServer,  for (var root in fileSystemRoots) "--filesystem-root=$root",  for (var entryPoint in entryPoints)    if (fileExists("lib/$entryPoint.json")) "lib/$entryPoint",  mainPath];
复制代码


Flutter 怎么写


到这里终于到正题了,如果熟悉 Web 前端,熟悉 React 的话,你会对下面要讲的异常的熟悉。



UI=F(state)


Flutter App 的一切从 lib/main.dart 文件的 main 函数开始:


import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Welcome to Flutter', home: Scaffold( appBar: AppBar( title: Text('Welcome to Flutter'), ), body: Center( child: Text('Hello World'), ), ), ); }}
复制代码


Dart 类 build 方法返回的便是 Widget,在 Flutter 中一切都是 Widget,包括但不限于


  • 结构性元素,menu,button 等

  • 样式类元素,font,color 等

  • 布局类元素,padding,margin 等

  • 导航

  • 手势


Widget 是 Dart 中特殊的类,通过实例化(Dart 中 new 是可选的)相互嵌套,你的这个 App 就是形如下图的一颗组件树(Dart 入口函数的概念,main.dart -> main())。



Flutter Widget Tree


2019-10-31 18:581606

评论

发布
暂无评论
发现更多内容

二极管及其应用

厉昱辰

电子技术 8月月更

语音直播系统——做好敏感词汇屏蔽打造绿色社交环境

开源直播系统源码

软件开发 语聊房 直播系统源码 语音直播系统

IDO预售DAPP系统开发(NFT挖矿)

薇電13242772558

dapp

华为研究院19级研究员几年心得,终成趣谈网络协议文档,附大牛讲解

冉然学Java

数据库 编程 微服务 网络协议 java\

开源一夏 | 不会吧,十分钟就能上手Prometheus与Grafana监控SpringBoot项目

知识浅谈

开源 8月月更 SpringBoot实战

基于深度学习的图像检索方法!

Geek_e369a5

图像搜索 图像检索

太厉害了!腾讯T4大牛把《数据结构与算法》讲透了,带源码笔记

冉然学Java

编程 算法 排序 java\ 数据结构与算法、

想做好分布式架构?这个知识点一定要理解透彻

王小凡

Java 程序员 分布式 高并发

兆骑科创创业赛事活动路演,高层次人才引进平台

兆骑科创凤阁

中科驭数等单位牵头发布行业首部DPU评测方法技术白皮书

硬科技星球

并发模型和I/O模型介绍

C++后台开发

后端开发 I/O模型 C/C++后台开发 C/C++开发 并发模型

国内IT市场还有发展吗?有哪些创新好用的IT运维工具可以推荐?

行云管家

云计算 多云管理 IT运维 云管理

浅析PM2实用入门指南

青年码农

Node pm2

开篇-开启全新的.NET现代应用开发体验

MASA技术团队

.net 云原生 后端

绝对最直白的MySQL MVCC机制总结,免费拿走

知识浅谈

开源 8月月更

史上最全!47个“数字化转型”常见术语合集,看完秒懂~

优秀

数字化转型 数字化业务转型

面试SQL语句,学会这些就够了!!!

程序员猪小哼

sql 实用SQl语句

AI+BI+可视化,Sugar BI架构深度剖析

百度Geek说

架构 数据

玉溪卷烟厂通过正确选择时序数据库 轻松应对超万亿行数据

TDengine

数据库 tdengine 时序数据库

Kubernetes资源编排系列之三: Kustomize篇

阿里云大数据AI技术

运维‘

这几年让你大呼惊人的AI应用,都离不开这项技术

小红书技术REDtech

人工智能 自然语言处理 nlp 自然语言 自然语言理解

Apache APISIX 2.15 版本发布,为插件增加更多灵活性

API7.ai 技术团队

开源 后端 API网关 APISIX 网关

大咖说·图书分享 | Serverless工程实践:从入门到进阶

大咖说

Serverless 工程实践

浅聊组合函数

掘金安东尼

前端 函数编程 8月月更

兆骑科创双创服务平台,创业赛事活动,投融资对接平台

兆骑科创凤阁

大数据培训如何部署一个健壮的Airflow

小谷哥

Python字体反爬之乐居字体反爬,一文看懂,一文学会

梦想橡皮擦

Python 爬虫 8月月更

《数字经济全景白皮书》银行业智能风控科技应用专题分析 发布

易观分析

金融 银行 数字经济全景白皮书

快速搞懂Seata分布式事务AT、TCC、SAGA、XA模式选型

知识浅谈

开源 8月月更

2022年值得尝试的7个MQTT客户端工具

EMQ映云科技

物联网 IoT mqtt 客户端 8月月更

一文搞懂│php 中的 DI 依赖注入

设计模式 依赖注入 8月月更 高级编程

写给前端工程师的 Flutter 教程(上)_大前端_云加社区_InfoQ精选文章