Flutter的异步编程详细

在 Dart 中,Future 和 Stream 是处理异步编程的核心工具。Future 用于处理单个异步操作的结果,而 Stream 用于处理一系列异步事件。为了更深入地理解它们,我们将从基础到高级用法详细讲解,并提供丰富的实例。


1. Future

Future 表示一个异步操作的结果,它可能成功(返回一个值)或失败(抛出异常)。

1.1 Future 的基本用法

创建 Future

javascript 复制代码
Future<String> fetchUserData() {
  return Future.delayed(Duration(seconds: 2), () => "User Data");
}

使用 then 和 catchError

scss 复制代码
void main() {
  fetchUserData().then((data) {
    print("Data received: $data");
  }).catchError((error) {
    print("Error: $error");
  });
}

使用 async/await

dart 复制代码
void main() async {
  try {
    String data = await fetchUserData();
    print("Data received: $data");
  } catch (error) {
    print("Error: $error");
  }
}

1.2 Future 的常用方法

whenComplete

无论 Future 成功还是失败,都会执行回调。

scss 复制代码
void main() {
  fetchUserData()
      .then((data) => print("Data received: $data"))
      .catchError((error) => print("Error: $error"))
      .whenComplete(() => print("Operation complete"));
}

Future.wait

等待多个 Future 完成。

dart 复制代码
void main() async {
  List<Future<String>> futures = [
    Future.delayed(Duration(seconds: 2), () => "Data 1"),
    Future.delayed(Duration(seconds: 3), () => "Data 2"),
    Future.delayed(Duration(seconds: 1), () => "Data 3"),
  ];

  List<String> results = await Future.wait(futures);
  print("All data received: $results");
}

Future.timeout

设置 Future 的超时时间。

dart 复制代码
void main() async {
  try {
    String data = await fetchUserData().timeout(Duration(seconds: 1));
    print("Data received: $data");
  } on TimeoutException {
    print("Timeout occurred");
  } catch (error) {
    print("Error: $error");
  }
}

1.3 Future 的高级用法

链式调用

javascript 复制代码
void main() {
  fetchUserData()
      .then((data) => data.toUpperCase())
      .then((data) => print("Uppercased Data: $data"))
      .catchError((error) => print("Error: $error"));
}

自定义 Future

csharp 复制代码
Future<int> customFuture() {
  return Future(() {
    // 模拟耗时操作
    return 42;
  });
}

void main() async {
  int result = await customFuture();
  print("Result: $result");
}

2. Stream

Stream 表示一系列异步事件,它可以发出多个值、错误或完成信号。

2.1 Stream 的基本用法

创建 Stream

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

使用 listen

dart 复制代码
void main() {
  countStream(5).listen(
    (data) => print("Data: $data"),
    onError: (error) => print("Error: $error"),
    onDone: () => print("Stream completed"),
  );
}

2.2 Stream 的常用方法

map

将 Stream 中的每个事件转换为另一个值。

javascript 复制代码
void main() {
  countStream(5)
      .map((data) => data * 2)
      .listen((data) => print("Mapped Data: $data"));
}

where

过滤 Stream 中的事件。

javascript 复制代码
void main() {
  countStream(5)
      .where((data) => data % 2 == 0)
      .listen((data) => print("Filtered Data: $data"));
}

take 和 skip

  • take(n):只取前 n 个事件。
  • skip(n):跳过前 n 个事件。
scss 复制代码
void main() {
  countStream(5)
      .take(3)
      .listen((data) => print("Taken Data: $data"));

  countStream(5)
      .skip(2)
      .listen((data) => print("Skipped Data: $data"));
}

reduce

将 Stream 中的所有事件合并为一个值。

javascript 复制代码
void main() {
  countStream(5)
      .reduce((a, b) => a + b)
      .then((sum) => print("Sum: $sum"));
}

2.3 Stream 的高级用法

StreamController

用于手动控制 Stream 的事件发射。

csharp 复制代码
void main() {
  var controller = StreamController<int>();

  controller.stream.listen((data) => print("Data: $data"));

  controller.add(1);
  controller.add(2);
  controller.add(3);

  controller.close();
}

broadcast

将单订阅 Stream 转换为广播 Stream,允许多个监听器同时监听。

scss 复制代码
void main() {
  var controller = StreamController<int>.broadcast();

  controller.stream.listen((data) => print("Listener 1: $data"));
  controller.stream.listen((data) => print("Listener 2: $data"));

  controller.add(1);
  controller.add(2);
  controller.add(3);

  controller.close();
}

StreamTransformer

用于将 Stream 转换为另一个 Stream。

javascript 复制代码
void main() {
  var transformer = StreamTransformer<int, String>.fromHandlers(
    handleData: (data, sink) => sink.add("Transformed: $data"),
    handleError: (error, stackTrace, sink) => sink.addError("Error: $error"),
    handleDone: (sink) => sink.close(),
  );

  countStream(5)
      .transform(transformer)
      .listen((data) => print(data));
}

2.4 Stream 在 Flutter 中的应用

StreamBuilder

StreamBuilder 是 Flutter 中用于根据 Stream 更新 UI 的组件。

scala 复制代码
import 'package:flutter/material.dart';

class StreamBuilderExample extends StatelessWidget {
  final Stream<int> stream = Stream.periodic(Duration(seconds: 1), (value) => value).take(10);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("StreamBuilder Example")),
      body: Center(
        child: StreamBuilder<int>(
          stream: stream,
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return Text("Error: ${snapshot.error}");
            }
            if (!snapshot.hasData) {
              return CircularProgressIndicator();
            }
            return Text("Data: ${snapshot.data}");
          },
        ),
      ),
    );
  }
}

3. Future 和 Stream 的结合

Future 和 Stream 可以结合使用,例如将 Future 的结果作为 Stream 的事件发射。

示例

dart 复制代码
void main() {
  Stream<int> stream = Stream.fromFuture(Future.delayed(Duration(seconds: 2), () => 42));

  stream.listen((data) => print("Data: $data"));
}

总结

  • Future:用于处理单个异步操作的结果,适合处理一次性事件。
  • Stream:用于处理一系列异步事件,适合处理连续的数据流。
  • Future 和 Stream 的结合:可以灵活处理复杂的异步场景。
相关推荐
麦麦麦当劳大王8 小时前
【油猴脚本】Boss直聘 岗位职责复制
开发语言·前端·javascript
小lu飞9 小时前
2026小红书小工具怎么制作:纯前端 ZIP 打包、沙箱限制与笔记挂载流程
前端·笔记·ai·ai编程
smallcelebration9 小时前
151 从0开始搭建后端项目
前端·firefox
wangruofeng9 小时前
手机和电脑传文件,除了微信还有 LocalSend
前端
excel10 小时前
基于 GPT 的自动发布文章接口方案:从一句话或一张图片生成并发布内容
前端·javascript·后端
其实防守也摸鱼11 小时前
个人学习 Pwn 思路:从基础到漏洞利用的进阶路径
大数据·前端·人工智能·chrome·算法·安全·网络安全
朱涛的自习室12 小时前
212 个需求、22 万行代码:Agent 接管开源项目的 19 天
android·前端·人工智能
aZhe的全栈知识分享12 小时前
AI 还原 Figma 效果总达不到预期?先别急着让它写代码
前端·后端·面试
review4454312 小时前
Codex Hooks 入门实战:生命周期事件、matcher 与5分钟跑通一个钩子
前端·agent·vibecoding
函数小陈12 小时前
阿里云部署DSH与RAM完成运维
前端·后端