【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 应用。在实际开发中,掌握这些异步工具对于提升应用性能和用户体验至关重要。

相关推荐
AiFlutter25 分钟前
Flutter通过 Coap发送组播
flutter
嘟嘟叽1 天前
初学 flutter 环境变量配置
flutter
iFlyCai1 天前
深入理解Flutter生命周期函数之StatefulWidget(一)
flutter·生命周期·dart·statefulwidget
sunly_1 天前
Flutter:photo_view图片预览功能
android·javascript·flutter
Summer不秃1 天前
Flutter中sqflite的使用案例
flutter
sunly_1 天前
Flutter:TweenAnimationBuilder自定义隐式动画
flutter
AiFlutter1 天前
Flutter-Web首次加载时添加动画
前端·flutter
Allen Su2 天前
【Flutter 问题系列第 84 篇】如何清除指定网络图片的缓存
flutter·缓存·如何清除指定网络图片的缓存·网络图片缓存
sunly_2 天前
Flutter:key的作用原理(LocalKey ,GlobalKey)
开发语言·javascript·flutter
AiFlutter2 天前
Flutter-flutter_blue_plus打包后无法进行设备扫描
flutter