Flutter的异步编程详细

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


1. Future

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

1.1 Future 的基本用法

创建 Future

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

使用 thencatchError

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"));
}

takeskip

  • 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 的结合

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

示例

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

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

总结

  • Future:用于处理单个异步操作的结果,适合处理一次性事件。
  • Stream:用于处理一系列异步事件,适合处理连续的数据流。
  • FutureStream 的结合:可以灵活处理复杂的异步场景。
相关推荐
IT_陈寒29 分钟前
垃圾回收器选错了,我的Java服务内存炸了
前端·人工智能·后端
月光下的丝瓜1 小时前
Flutter 国内安装指南
前端·flutter
玄星啊1 小时前
AI 编程的第 30 天,我怀念古法 Coding 了
前端·ai编程
Jolyne_1 小时前
Angular基础速通
前端·angular.js
锋行天下2 小时前
半秒开!还有谁!!!
前端·vue.js·架构
代码搬运媛3 小时前
git 下中文文件名乱码问题解决
前端
CaffeinePro3 小时前
告别知识点零散!React零基础通关,从环境搭建到Ant Design页面实战
前端·react.js
cidy_984 小时前
水龙头领不到测试币?手把手用 Hardhat 本地环境零门槛学以太坊交易
前端
因_崔斯汀4 小时前
Three.js 3D 地图特效与材质实现指南
前端
angerdream4 小时前
手把手编写儿童手机远程监控App之vue3用 AI Agent生成菜单
前端