【Flutter】Dart:异步

在现代应用开发中,异步编程是不可或缺的部分,尤其是在开发用户界面、网络请求、文件操作等涉及长时间执行的操作时,异步能避免阻塞主线程,从而提升应用的响应速度和用户体验。在 Dart 中,异步编程主要依靠 FutureStream ,此外,Dart 还支持 生成器函数 来简化某些异步操作的实现。

本教程将深入介绍 Dart 中的异步编程,涵盖 FutureStream 以及生成器函数的使用。

异步编程概述

在 Dart 中,异步编程的主要目标是避免阻塞主线程(UI 线程),让长时间运行的任务在后台执行,同时主线程可以继续响应用户操作。异步编程通过 FutureStream 来实现。

  • Future:表示一个可能在将来某个时间完成的异步操作,可以成功返回一个结果或抛出错误。
  • Stream :类似于 Future,但可以在一段时间内多次返回数据。
  • 生成器函数 :一种简化异步数据生成的机制,通常与 async*yield 关键字结合使用。

Future详解

Future 是 Dart 异步编程的基础,它表示一个将在未来完成的计算。Future 有两种状态:未完成(pending)完成(completed) 。当一个异步操作完成时,Future 要么返回结果(成功),要么抛出异常(失败)。

创建 Future

Future 可以通过多种方式创建,包括 Future.value()Future.error() 和异步函数 async 的返回值。

示例:使用 Future.value()

dart 复制代码
void main() {
  Future<String> future = Future.value('Hello, Dart Future!');
  future.then((value) => print(value));
}

示例:使用异步函数

dart 复制代码
Future<String> fetchData() async {
  // 模拟网络请求,延迟 2 秒返回结果
  await Future.delayed(Duration(seconds: 2));
  return 'Data fetched!';
}

void main() async {
  print('Fetching data...');
  String data = await fetchData();
  print(data);
}

在上面的示例中,fetchData 是一个异步函数,返回一个 Future<String>,并通过 await 关键字等待 Future 完成。在调用该函数时,主线程不会被阻塞。

thencatchError 处理结果

使用 Future 时,结果通常通过 then() 方法处理,错误通过 catchError() 处理。then() 方法会在 Future 完成后执行回调。

示例:处理结果和错误

dart 复制代码
void main() {
  Future<int> future = Future(() {
    return 42;
  });

  future.then((value) {
    print('Future completed with value: $value');
  }).catchError((error) {
    print('An error occurred: $error');
  });
}

asyncawait

在 Dart 中,asyncawait 提供了一种简洁的语法来处理异步操作,使代码看起来更像同步代码。

示例:使用 asyncawait

dart 复制代码
Future<int> fetchNumber() async {
  await Future.delayed(Duration(seconds: 1));  // 模拟耗时操作
  return 100;
}

void main() async {
  print('Start fetching number...');
  int number = await fetchNumber();
  print('Fetched number: $number');
}

通过 async 标记一个函数为异步,使用 await 等待 Future 完成。在上面的例子中,fetchNumber() 返回一个 Future<int>,主线程等待该 Future 完成后继续执行。

Stream详解

Future 不同,Stream 代表一个异步数据的序列,可以多次发出数据。在 Dart 中,Stream 是处理大量异步事件(如用户输入、文件操作、网络请求)的重要工具。

创建 Stream

Stream 主要有两种类型:单订阅流(single-subscription stream)广播流(broadcast stream)

  • 单订阅流:只能有一个监听器。
  • 广播流:可以有多个监听器,通常用于事件广播。

示例:单订阅流

dart 复制代码
void main() {
  Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);

  stream.listen((value) {
    print('Stream value: $value');
  });
}

示例:广播流

dart 复制代码
void main() {
  Stream<int> stream = Stream<int>.periodic(Duration(seconds: 1), (count) => count).asBroadcastStream();

  stream.listen((value) {
    print('Listener 1: $value');
  });

  stream.listen((value) {
    print('Listener 2: $value');
  });
}

在广播流中,多个监听器可以同时监听同一个 Stream,在上面的例子中,两个监听器同时监听并处理同一个 Stream

监听 Stream

通过 listen() 方法可以订阅 Stream,并处理流中的数据。

示例:处理 Stream

dart 复制代码
Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    yield i;
    await Future.delayed(Duration(seconds: 1));  // 模拟延迟
  }
}

void main() async {
  Stream<int> stream = countStream(5);

  await for (int value in stream) {
    print('Stream value: $value');
  }
}

在这个例子中,countStream() 是一个生成器函数,通过 yield 发出数据,并通过 await for 逐个读取 Stream 中的数据。

转换 Stream

Stream 提供了许多方法用于转换流中的数据,比如 map()where()reduce() 等。

示例:转换 Stream

dart 复制代码
void main() {
  Stream<int> stream = Stream.fromIterable([1, 2, 3, 4, 5]);

  stream
    .map((value) => value * 2)
    .where((value) => value > 5)
    .listen((value) {
      print('Transformed Stream value: $value');
    });
}

这个例子展示了如何使用 map()where() 对流中的数据进行转换和过滤。

生成器函数

生成器函数可以生成一系列异步数据,它们使用 async*yield 关键字。生成器函数返回一个 Stream,可以逐步生成多个数据项。

sync*async*

  • sync*:同步生成器,用于生成一系列同步数据。
  • async*:异步生成器,用于生成一系列异步数据。

示例:使用 sync*

dart 复制代码
Iterable<int> syncGenerator(int max) sync* {
  for (int i = 1; i <= max; i++) {
    yield i;
  }
}

void main() {
  var generator = syncGenerator(5);

  for (var value in generator) {
    print('Generated value: $value');
  }
}

示例:使用 async*

dart 复制代码
Stream<int> asyncGenerator(int max) async* {
  for (int i = 1; i <= max; i++) {
    yield i;
    await Future.delayed(Duration(seconds: 1));
  }
}

void main() async {
  await for (var value in asyncGenerator(5)) {
    print('Generated async value: $value');
  }
}

async* 生成器与 sync* 不同的是,它会返回 Stream,并且可以处理异步任务。上面的例子中,asyncGenerator() 生成异步数据,并通过 await for 逐步读取。

总结

Dart 中的异步编程通过 FutureStream 和生成器函数为开发者提供了强大的工具,帮助处理复杂的异步操作。Future 用于处理一次性的异步任务,Stream 适合处理一系列异步事件,而生成器函数则提供了简洁的异步数据生成机制。

通过合理使用异步编程模式,开发者可以编写出高效、响应迅速的 Flutter 应用。在实际开发中,掌握这些异步工具对于提升应用性能和用户体验至关重要。

相关推荐
problc7 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
lqj_本人15 小时前
鸿蒙next选择 Flutter 开发跨平台应用的原因
flutter·华为·harmonyos
lqj_本人19 小时前
Flutter&鸿蒙next 状态管理框架对比分析
flutter·华为·harmonyos
起司锅仔1 天前
Flutter启动流程(2)
flutter
hello world smile1 天前
最全的Flutter中pubspec.yaml及其yaml 语法的使用说明
android·前端·javascript·flutter·dart·yaml·pubspec.yaml
lqj_本人1 天前
Flutter 的 Widget 概述与常用 Widgets 与鸿蒙 Next 的对比
flutter·harmonyos
iFlyCai1 天前
极简实现酷炫动效:Flutter隐式动画指南第二篇之一些酷炫的隐式动画效果
flutter
lqj_本人1 天前
Flutter&鸿蒙next 中使用 MobX 进行状态管理
flutter·华为·harmonyos
lqj_本人1 天前
Flutter&鸿蒙next 中的 setState 使用场景与最佳实践
flutter·华为·harmonyos
hello world smile1 天前
Flutter常用命令整理
android·flutter·移动开发·android studio·安卓