当前位置: 首页 > article >正文

【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()

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

示例:使用异步函数

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 完成后执行回调。

示例:处理结果和错误

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

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)

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

示例:单订阅流

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

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

示例:广播流

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

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

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*

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*

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


http://www.kler.cn/news/354672.html

相关文章:

  • docker容器里的时间不对,linux解决方案
  • 机器学习——向量化
  • 学习第三十六行
  • 【实战案例】树形字典结构数据的后端解决方案
  • 雷达数据与影像数据直观对比
  • YOLO的更新迭代
  • 基于SpringBoot的企业客户管理系统的设计与实现(论文+源码)_kaic
  • 软件测试CNAS实验室软件维护性测试作业指导书怎么写
  • AI大模型与相对论的结合点的思考、应用及相对论原理与公式表达
  • C++之《剑指offer》学习记录(9):字符串替换空格
  • 3D Slicer 教程五 ---- 基本功能介绍(二)
  • 五款软件神器
  • 萱仔求职复习系列——力扣
  • KafKa 集群【docker compose】
  • 刚刚,ChatGPT推出Windows客户端!
  • 111 - Lecture4
  • 如何保证接口幂等性?
  • C语言 sizeof 的介绍,以及sizeof计算数组名、 数组首地址、数组的元素之间的区别
  • 华为OD题库刷题记录1(掌握的单词个数+手机APP防沉迷+找朋友+流浪地球)
  • 小马识途海外媒体推广有何优势?