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 的结合:可以灵活处理复杂的异步场景。
相关推荐
申朝先生15 分钟前
用CSS画一条0.5px的线
前端·javascript·css
雪碧聊技术1 小时前
element-plus中Autocomplete自动补全输入框组件的使用
前端·javascript·vue.js·自动补全输入框·autocomplete
浪遏1 小时前
当你向面试官朗诵单例模式时 ,ta说talk is cheep , show me the code🤡
前端·设计模式·面试
zczlsy112 小时前
webpack介绍
前端·webpack·node.js
六个点2 小时前
关于vue的面试考点总结🤯
前端·vue.js·面试
浪遏3 小时前
今晚揭开单例模式的面纱~
前端·设计模式·面试
驯龙高手_追风3 小时前
谷歌Chrome或微软Edge浏览器修改网页任意内容
前端·chrome·edge
luckyext4 小时前
Postman发送GET请求示例及注意事项
前端·后端·物联网·测试工具·小程序·c#·postman
小满zs4 小时前
React第三十章(css原子化)
前端·react.js
一直在学习的小白~4 小时前
前端项目中创建自动化部署脚本,用于 Jenkins 触发 npm run publish 来完成远程部署
前端·自动化·jenkins