Flutter学习笔记:02. Dart 进阶

158 阅读1分钟

1. extension(扩展)

  • extension 关键字在 Dart 2.7 及其以上才支持
    • sdk:">=2.7.0<3.0.0"
  • extension 可以扩展对象的内容
    • extension StringExtension on String { // 扩展的内容 }
    • 扩展不仅可以定义方法,还可以定义 settergetteroperator
  • 使用
    • 声明扩展
    • 引入扩展
    • 使用扩展(String.扩展内容
// 扩展内置类
extension StringExtension on String {
  // 将字符串形式的数字,转成数字
  parseInt() {
    return int.parse(this);
  }
}

// 扩展自定义类
class Person {
  say() {
    print('Say something');
  }
}

extension StudentPerson on Person {
  study() {
    print('Study hard');
  }
}

void main() {
  String number = '20';
  print(number.parseInt()); // 20

  var p = new Person();
  p.say(); // Say something
  p.study(); // Study hard
}

2. call

  • 在类中可以声明 call 方法 (方法名不能变)
  • 当我们将类的实例,用作函数时,会自动调用 call 方法
class IOSPhone {
  call(String num) {
    print('phone number is $num');
  }
}

void main() {
  var phone = IOSPhone();
  phone('911'); // phone number is 911, 把类的实例,当做函数来使用
  
  IOSPhone()('911'); // 简写方式,(先实例化,再调用)
}

3. noSuchMethod

  • 当我们调用了一个类的,未定义的方法时,Dart会自动调用 noSuchMethod
  • 使用前提
    • 类中声明了 noSuchMethod (否则调用默认的 noSuchMethod)
    • 实例化对象必须用 dynamic 来修饰
      • dynamic p = Person();
    • 调用的是未定义方法(p.undefinedMethod();
class Person {
  say() {
    print('say something');
  }
  
  @override
  noSuchMethod(Invocation invocation) {
    print('未定义的方法');
    // return super.noSuchMethod(invocation);
  }
}

void main() {
  dynamic p = new Person();
  p.say();
  p.study(); // 未定义的方法
}

4. hashCode

  • hashCode 是 Dart 对象的唯一标识
  • hashCode 表现为一串数字
  • Dart 中的每个对象都有 hashCode
  • 我们可以通过 hashCode 来判断两个对象是否相等
class Person {
  say() {
    print('say something');
  }
}

void main() {
  var p1 = new Person();
  print(p1.hashCode); // 1038920657

  var p2 = new Person();
  print(p2.hashCode); // 806325257
}

5. typedef

  • typedef 可以用来自定义类型(别名),目的是让程序的可读性更强
    • 我们可以在声明泛型时,使用自定义的类型
  • 语法:
    • typedef function_name(parameters);
    • typedef variable_name = List<int>;
  • 版本声明
    • sdk: ">=2.13.0"
    • 2.13之前,typedef仅限于函数类型
    • 2.13之后,typedef可以定义非函数类型
typedef MathOperation(int a, int b);

// 声明加法运算
add(int a, int b) {
  print('加法运算:' + (a + b).toString());
  return a + b;
}

// 声明减法运算
sub(int a, int b) {
  print('减法运算:' + (a - b).toString());
  return a - b;
}

// 声明加法运算
add3(int a, int b, int c) {
  print('加法运算3:' + (a + b + c).toString());
  return a + b + c;
}

// 计算器
calculator(int a, int b, MathOperation op) {
  print('计算器:');
  op(a, b);
}

void main() {
  print(add is MathOperation); // true
  print(add is Function); // true

  print(sub is MathOperation); // true
  print(sub is Function); // true

  print(add3 is MathOperation); // false
  print(add3 is Function); // true

  MathOperation op = add;
  op(10, 20); // 加法运算:30

  op = sub;
  op(20, 10); // 减法运算:10
  
  calculator(8, 5, add);
  calculator(8, 5, sub);
}

6. 异步编程

6.1. 单线程(EventLoop)

  • Dart 单线程的核心包括:主线程、微任务、宏任务
    • 微任务队列
      • 微任务队列包含微任务,主要通过 scheduleMicrotask 来调度
    • 事件队列
      • 事件队列包含外部事件,例如:I/O、Timer、绘制事件等
  • 同步与异步
    • 同步(4*100米,接力赛)
    • 异步(100米中有8个跑道)

image.png

6.2. Isolate 多线程

  • lsolate 是 Dart 中的线程

    • Dart 中的线程是以隔离(lsolate)的方式存在的
    • 每个 lsolate 都有自己独立的,私有内存块(多个线程不共享内存)
    • 没有共享内存,就不需要竞争资源,就不需要锁(不用担心死锁问题)
  • 所有的 Dart 代码,都运行在 lsolate

    • lsolate提供了 Dart | Flutter 的运行环境
    • 微任务队列、事件队列、事件轮训(EventLoop)都在 lsolate 中进行
  • 多线程经常用来解决耗时较长的异步任务

  • lsolate 类用来管理线程(创建、暂停、杀死lsolate线程)

    • lsolate.spawn();
    • lsolate.spawnUri();
    • lsolate.pause();
    • lsolate.kill();

6.2.1. 多线程 - 创建

  • Future<lsolate> lsolate.spawn(entryPoint, message);
    • import 'dart:isolate';
    • entryPoint 必须是一个顶层方法或者静态方法
    • message
        1. Dart 原始数据类型,如:nullboolintdoubleString
        1. SendPort实例- ReceivePort().sendPort
      • 包含 1 和 2 的 listmap,也可以嵌套
  • compute()
    • import 'package:flutter/foundation.dart';

6.3. Future

6.3.1. 什么是 Future

  • 概念
    • Future 是 Dart 中的类,我们可以通过 Future 实例,封装一些异步任务
    • Future 的含义是未来。未来要执行的一些任务,我们可以放到 Future 中
  • Future 有三种状态
    • 未完成(Uncompleted)
    • 已完成,并返回数据(Completed with data)
    • 已完成,但返回报错(Completed with error)

image.png

6.3.2. 获取 Future 实例

  • 自动返回
    • final myFuture = http.get('https://my.image.url');
    • final myFuture = SharedPreferences.getInstance;
  • 手动创建
    • final myFuture = Future(() {return 123;});
    • final myFuture = Future.error(Exception());
    • final myFuture = Future.delayed(Duration(seconds: 5), () => 123);
  • Future 状态相关的方法
    • 创建
      • Uncompleted
    • then()
      • Completed with data
    • catchError()
      • Completed with error
    • whenComplete()
      • Completed with data + Completed with error
void main() {
  // 创建 Future 实例
  final f = Future(() {
    print('Create the future');
    
    return 123;
  });
  
  print(f);
  
  f.then((value) => print(value));
  
  print('Done with main');
}
void main() {
  Future.delayed(Duration(seconds: 2), () {
    return 123;
    // throw Error();
  }).then((value) {
    print(value);
  }).catchError(
    (err) {
      print(err);
    },
    test: (error) => error.runtimeType == String,
  ).whenComplete(() {
    print('All Completed');
  });
}

6.3.3. Future 执行顺序

  • Future 默认是异步任务,会被丢到事件队列(event queue)中
  • Future.sync()
    • 同步任务,同步执行(不会被丢到异步队列中)
  • Future.microtask()
    • 微任务,会丢到 microtask queue 中,优先级比事件任务高
  • Future.value(val)
    • val 是常量(等同于 microtask
    • val 是异步(按照异步逻辑处理)
void main() {
  print('start');
  
  Future(() => print('Future() task')); // event queue
  Future.sync(() => print('Future.sync() task'));
  
  // 如果 value 后面的值是异步,则按照异步的逻辑进行处理
  Future.value(Future(() => print('Future.value future task')));
    
  // 如果 value 后面的值是常量,那么 Future.value 创建的是微任务
  Future.value('Future.value() const task').then((value) => print(value));
  Future.microtask(() => print('Future.microtask() task')); // microtask queue
  
  print('end');
  
  /*
   *  start
      Future.sync() task
      end
      Future.value() const task
      Future.microtask() task
      Future() task
      Future.value future task
   * */
}

6.3.4. Future 多任务

  • Future.any(futures);
    • 返回最先完成的 Future 结果
  • Future.wait(futures);
    • 等待所有的 Future 执行完成,并收集所有 Future 的返回结果
  • Future.doWhile(action);
    • 按照条件遍历执行多个 Future
  • Future.forEach(elements, action);
    • 遍历一个给定的集合,根据集合元素执行多个 Future
void main() {
  print('start');

  // 返回最先完成的异步任务
  Future.any([
    Future.delayed(Duration(seconds: 4)).then((value) => 1),
    Future.delayed(Duration(seconds: 2)).then((value) => 2),
    Future.delayed(Duration(seconds: 3)).then((value) => 3),
  ]).then((value) => print('多个 Future 的最快的返回结果是:$value'));

  // 等待所有异步任务完成,并收集所有异步任务的结果
  Future.wait([
    Future.delayed(Duration(seconds: 4)).then((value) {
      print('Future 1');
      return 1;
    }),
    Future.delayed(Duration(seconds: 2)).then((value) {
      print('Future 2');
      return 2;
    }),
    Future.delayed(Duration(seconds: 3)).then((value) {
      print('Future 3');
      return 3;
    }),
  ]).then((value) => print('所有 Future 的执行结果是:$value'));

  var i = 0;
  Future.doWhile(() {
    i++;

    return Future.delayed(Duration(seconds: 2), () {
      print(
          'Future.doWhile() $i, 当前时间:${DateTime.now().microsecondsSinceEpoch}');
      return i < 6;
    }).then((value) {
      print(value);
      return value;
    });
  }).then((val) {
    print('Future.doWhile() then:null');
  });

  Future.forEach([1, 2, 3], (element) {
    return Future.delayed(Duration(seconds: 2), () {
      print('当前元素:$element');
      return element.toString() + '_AAA';
    }).then((value) => print('处理后的结果:$value'));
  });

  print('end');
}

6.3.5. FutureBuilder

  • FutureBuilder 是 Flutter SDK 中提供的异步组件。
    • FutureBuilder 是一个类,接受 Future 数据,并将数据渲染成页面
    • import 'package:flutter/material.dart';
  • FutureBuilder 中有 3 个属性
    • future
    • initialData
    • builder(context, snapshot)

6.3.5.1. FutureBuilder - snapshot

  • snapshot.connectionState
    • ConnectionState.none (未连接异步任务)
    • ConnectionState.waiting (连接异步任务,等待交互)
    • ConnectionState.active (正在交互)
    • ConnectionState.done (异步任务完成)
  • snapshot.hasData (Completed with data)
    • snapshot.data
  • snapshot.hasError (Completed with error)

image.png

6.4. Stream

6.4.1. 什么是 Stream

  • Stream 是 Dart 中的异步数据流,可以连续不断地返回多个数据

    • Future 是异步,但只返回一个值
    • Stream 也是异步,可以返回多个值(数据流)
  • Stream 相关的API

    • 通过 listen 进行数据监听
    • 通过 error 接收失败状态
    • 通过 done 来接收结束状态
  • Stream 类型

    • Single-Subscription(单一订阅)
      • 数据流只能被 listen 一次(listen 多次会报错)
      • StremaController().stream
      • Stream stream = Stream.fromlterable(data)
    • Broadcast (广播)
      • 数据流可以被 listen 多次
      • StremaController<int>.broadcast();
      • stream.asBroadcastStream();
import 'dart:async';

void main() {
  // 创建单一订阅数据流
  final StreamController controller = StreamController();
  
  // 第一次监听
  controller.stream.listen((event){
    print('Data is $event');
  });
  
  // 第二次监听,会报错
//   controller.stream.listen((event){
//     print('Data is $event');
//   });
  
  // 给数据流添加数据
  controller.sink.add('abc');
  controller.sink.add('123');
}
import 'dart:async';

void main() {
  // 创建广播留
  StreamController controller = StreamController.broadcast();
  
  // 第一次监听
  controller.stream.listen((event){
    print('Data1 is $event');
  });
  
  controller.sink.add('abc');
  
  // 第二次监听
  controller.stream.listen((event){
    print('Data2 is $event');
  });
  
  // 给数据流添加数据
  controller.sink.add('123');
}

6.4.2. 创建 Stream

  • StreamController
    • sink
    • stream
  • Stream 类
    • Stream.fromFuture()
    • Stream.fromFutures()
    • Stream.fromIterable()
    • Stream.periodic()

image.png

6.4.3. 操作 Stream

6.4.4. StreamBuilder

6.5. Async / Await

6.6. Generator