在 Flutter 中,响应式编程是一种重要的设计理念,而 Stream 是实现异步数据流和响应式UI更新的关键工具。本文将深入剖析 Flutter 中的 Stream,带你了解它的本质、单播和多播的区别,以及如何使用 StreamBuilder 和 StreamController 来构建流式响应式应用。
什么是 Stream?
Stream 是 Dart 语言提供的一种异步数据序列,可以理解为数据的“时间轴”,它会随着时间推移不断发出数据事件。Flutter 和 Dart 生态中,Stream 广泛用于处理网络请求、用户输入、事件监听等场景。
Stream 中的数据是按顺序依次到达的,这使得我们可以优雅地处理异步数据流。
单播(Single-subscription)与多播(Broadcast)Stream
单播 Stream
单播流只能有一个监听者(listener),也就是说,只能被一个订阅者订阅:
- 适用于一次性任务,如网络请求结果、单次事件处理。
- 当有多个订阅者尝试监听同一个单播流时,会抛出异常。
Stream<int> singleStream = Stream.fromIterable([1, 2, 3]);
singleStream.listen((value) {
print('Listener 1: $value');
});
// 如果再添加另一个监听,会报错
// singleStream.listen((value) => print('Listener 2: $value')); // 报错!
多播(Broadcast)Stream
多播流允许多个监听者同时订阅。它更适合广播事件,比如 UI 事件、传感器数据等。
通过调用 asBroadcastStream(),可以将单播流转换成多播流:
Stream<int> broadcastStream = Stream.fromIterable([1, 2, 3]).asBroadcastStream();
broadcastStream.listen((value) {
print('Listener 1: $value');
});
broadcastStream.listen((value) {
print('Listener 2: $value');
});
或者直接创建多播流:
StreamController<int> controller = StreamController<int>.broadcast();
StreamController:主动控制数据流
StreamController 是用来创建和控制 Stream 的核心类,它允许我们手动添加数据、错误或关闭事件到流中。它是连接数据生产者和消费者的桥梁。
创建 StreamController
final controller = StreamController<int>();
// 监听数据
controller.stream.listen((data) {
print('Received: $data');
});
// 添加数据
controller.sink.add(1);
controller.sink.add(2);
// 关闭流
controller.close();
Broadcast Controller
如果希望流支持多个监听者,需创建广播类型的控制器:
final broadcastController = StreamController<int>.broadcast();
broadcastController.stream.listen((data) => print('Listener 1: $data'));
broadcastController.stream.listen((data) => print('Listener 2: $data'));
broadcastController.sink.add(10);
broadcastController.sink.add(20);
broadcastController.close();
StreamBuilder:Flutter 中的流式UI构建器
StreamBuilder 是 Flutter 框架中专门用来监听 Stream 并根据流数据动态构建 UI 的 Widget。它使得响应式编程变得简单直观。
基本用法
Stream<int> numberStream = Stream.periodic(Duration(seconds: 1), (count) => count).take(10);
StreamBuilder<int>(
stream: numberStream,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
return Text('Current number: ${snapshot.data}');
} else {
return Text('Stream ended');
}
},
)
重要属性
- stream:要监听的 Stream。
- builder:每当流发出新事件时调用,用于构建 Widget。
- snapshot:包含当前流的状态和最新数据。
常见使用场景
- 网络数据加载和刷新
- 实时计时器或动画
- 用户输入事件监听
- 传感器数据显示
总结
| 组件 | 功能 | 特点和注意点 |
|---|---|---|
| Stream | 异步数据流 | 单播(默认)、多播(广播) |
| StreamController | 手动创建和管理流 | 支持广播类型,添加数据、错误,控制流的生命周期 |
| StreamBuilder | 响应流数据,构建UI | 绑定流和UI,自动监听流变化,简化响应式UI开发 |
Flutter 中的 Stream 机制为异步数据处理和响应式编程提供了强大的支持,理解并灵活使用单播、多播流,结合 StreamController 和 StreamBuilder,可以极大地提升你的应用性能和用户体验。