在 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
的结合:可以灵活处理复杂的异步场景。