Flutter初识-Dart

401 阅读8分钟

前言

Flutter官网:flutterchina.club/

Dart官网:www.dartcn.com/

背景

写这篇文章的初衷是用来是巩固和温习flutter相关知识,说起来也惭愧。其实在19年的时候,就已经接触并使用过一段时间的flutter。后面由于公司业务调整,flutter项目被砍掉了,后续再未去深入研究(其实是懒吧)。正好现在有时间,重新梳理温习一遍。

Flutter介绍

Flutter是谷歌的高性能、跨端UI框架,可以通过一套代码,支持iOS、Android、Windows/MAC/Linux等多个平台,且能达到原生性能。 Flutter也可以与平台原生代码进行混合开发。在全世界,Flutter正在被越来越多的开发者和组织使用,并且Flutter是完全免费、开源的。

上述是官方对Flutter的介绍,当我们想要实现跨平台,完全可以使用Flutter。

Flutter环境配置

官网有详细的Flutter环境配置文档,大家可以按需进行,这里就不过多介绍了。注意由于国内网络限制的原因,最好先配置网络环境变量:

export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

Dart语法

Dart是谷歌开发的计算机编程语言,它被用于web、服务器、移动应用和物联网等领域的开发。

Dart是面向对象的、类定义的、单继承的语言。它的语法类似C语言,可以转译为JavaScript,支持接口(interfaces)、混入(mixins)、抽象类(abstract classes)、具体化泛型(reified generics)、可选类型(optional typing)和sound type system

注意

  • 任何保存在变量中的都是一个对象,并且所有的对象都是对应一个类的实例。 无论是数字,函数和null都是对象。所有对象继承自Object类。
  • 尽管Dart是强类型的,但是Dart可以推断类型,所以类型注释是可选的。如果要明确说明不需要任何类型,需要使用特殊类型 dynamic 。

变量

声明变量

  • 创建一个变量并初始化
var name = "Cob";
  • 变量仅存储对象引用,这里的变量是name存储了一个String类型的对象引用。 “Cob” 是这个 String 类型对象的值。name变量的类型被推断为String。但是也可以通过指定类型的方式,来改变变量类型。 如果对象不限定为单个类型,可以指定为对象类型或动态类型。
dynamic name = "Cob";
Object name = "Cob";
  • 也可以直接显示声明变量的类型
String name = "Cob";

Final 和 Const

  • 使用过程中从来不会被修改的变量, 可以使用final或const, 而不是var或者其他类型,Final变量的值只能被设置一次;const变量在编译时就已经固定(const变量是隐式final的类型) 最高级final变量或类变量在第一次使用时被初始化。简单来讲,final修饰的变量在运行时才会赋值,const修饰的变量在编译期就已经赋值。
final name = "Cob";
const name = "Coby";

空安全

  • Dart是可以保证空安全,但是我们可以定义为空,在使用时必须判空,不然会爆出异常。

  • 默认为不可空,必须在定义时初始化。

int i = 8;
  • 定义为可空类型,对于可空变量,我们在使用前必须判空。
int? j; 
  • 如果我们预期变量不能为空,但在定义时不能确定其初始值,则可以加上late关键字,表示会稍后初始化,但是在正式使用它之前必须得保证初始化过了,否则会报错
late int k;
k=9;

内建类型

类型说明
NumberDart 的 Number 类型只有 int 和 double,支持更多类型请参考dart:math
StringDart 字符串是一组 UTF-16 单元序列,字符串通过单引号或者双引号创建
BooleanDart 使用 bool 类型表示布尔值。Dart 只有字面量 true 和 false 是布尔类型,这两个对象都是编译时常量
List在 Dart 中的 Array 就是 List 对象,通常称之为 List
Set在 Dart 中 Set 是一个元素唯一且无序的集合,Dart 中 Map 通过 Map 字面量和 Map 类型来实现
Map通常来说,Map 是用来关联 keys 和 values 的对象。keys和values可以是任何类型的对象。在一个Map对象中一个key只能出现一次。但是value可以出现多次。Dart中Map通过Map字面量和Map类型来实现
Rune在Dart中,Rune用来表示字符串中的UTF-32编码字符
Symbol一个 Symbol 对象表示 Dart 程序中声明的运算符或者标识符

方法

  • Dart 是一门真正面向对象的语言, 甚至其中的函数也是对象,并且有它的类型 Function 。 这也意味着函数可以被赋值给变量或者作为参数传递给其他函数。 也可以把 Dart 类的实例当做方法来调用。
  • 下面三种方式都是定义同一种方法
//显示声明返回值
bool isReal() {
  return 1 == 2;
}

//不显示声明
isReal() {
  return 1 == 2;
}

//lambda表达式
isReal() => 1 == 2;
  • 注意:所有函数都会返回一个值。如果没有明确指定返回值,函数体会被隐式的添加return null; 语句。

控制流程语句

运算符说明
if 和 elseDart 支持 if-else 语句,其中 else 是可选的
for 循环进行迭代操作,可以使用标准 for 语句
while 和 do-whilewhile 循环在执行前判断执行条件,do-while 循环在执行后判断执行条件
break 和 continue使用 break 停止程序循环,使用 continue 跳转到下一次迭代
switch 和 case在 Dart 中 switch 语句使用 == 比较整数,字符串,或者编译时常量。 比较的对象必须都是同一个类的实例(并且不可以是子类), 类必须没有对 == 重写。 枚举类型 可以用于 switch 语句
assert如果 assert 语句中的布尔条件为 false , 那么正常的程序执行流程会被中断

  • Dart 是一种基于类和 mixin 继承机制的面向对象的语言。 每个对象都是一个类的实例,所有的类都继承于 Object. 。 基于 * Mixin 继承* 意味着每个类(除 Object 外) 都只有一个超类, 一个类中的代码可以在其他多个继承类中重复使用。

  • 在这里要特别说明一下接口,每个类都隐式的定义了一个接口,接口包含了该类所有的实例成员及其实现的接口。 如果要创建一个 A 类,A 要支持 B 类的 API ,但是不需要继承 B 的实现, 那么可以通过 A 实现 B 的接口

// person 类。 隐式接口里面包含了 greet() 方法声明。
class Person {
  // 包含在接口里,但只在当前库中可见。
  final String _name;

  // 不包含在接口里,因为这是一个构造函数。
  Person(this._name);

  // 包含在接口里。
  String greet(String who) => 'Hello, $who. I am $_name.';
}

String greetBob(Person person) => person.greet('Bob');

// person 接口的实现。
class Impostor implements Person {
  @override
  get _name => '';

  @override
  String greet(String who) => 'Hi $who. Do you know who I am?';
}

void main() {
  print(greetBob(Person('Kathy')));
  print(greetBob(Impostor()));
}
  • Dart 是不支持多继承的,但是它支持 mixin,简单来讲 mixin 可以 “组合” 多个类,我们通过一个例子来理解。
class Fruits {
  say() {
    print("all Fruits");
  }
}

mixin Apple {
  say() {
    print("i am Apple");
  }
}

mixin Banana {
  say() {
    print("i am Banana");
  }
}

class Pear extends Fruits with Apple, Banana {}

异步操作

  • Dart 库中包含许多返回 Future 或 Stream 对象的函数. 这些函数在设置完耗时任务(例如 I/O 操作)后, 就立即返回了,不会等待耗任务完成。 使用 async 和 await 关键字实现异步编程。 可以让你像编写同步代码一样实现异步操作。

Future

  • 在 Dart 库中随处可见 Future 对象,通常异步函数返回的对象就是一个 Future。 当一个 future 完成执行后,future 中的值就已经可以使用了。
  • 注意:在直接使用 Future API 前,首先应该考虑 await 来替代。 代码中使用 await 表达式会比直接使用 Future API 更容易理解。
  • 简单示例
main() {
  //方式一:  
  Future future = Future.value(20);
  future.then((value) => print(value));
  //方式二:可以直接创建Future
  Future(() => print("start")).then((value) => print("complete")).onError((error,   stackTrace) => print("error"));

}

async 和 await

  • 使用 async 和 await 关键字的代码是异步的,要使用 await , 代码必须在 异步函数(使用 async 标记的函数)中
main() {
  start();
}

start() async {
  print("start");
  await request();
  print("end");
}

request() {
  print("request");
}

Stream

  • Stream 也是用于接收异步事件数据,和 Future 不同的是,它可以接收多个异步操作的结果(成功或失败)。 也就是说,在执行异步任务时,可以通过多次触发成功或失败事件来传递结果数据或错误异常。 Stream 常用于会多次读取数据的异步任务场景,如网络内容下载、文件读写等。
Stream.fromFutures([
  Future.delayed(Duration(seconds: 1), () {
    return "start";
  }),
  Future.delayed(Duration(seconds: 3), () {
    return AssertionError("timeout");
  })
]).listen((event) {
  print(event);
}, onError: (e) {
  print(e.toString());
});

参考

book.flutterchina.club/

www.cnblogs.com/lxlx1798/p/…