StreamSubscription
官方解释:
订阅来自 [Stream] 的事件。当您使用 [Stream.listen] 监听 [Stream] 时,将返回 [StreamSubscription] 对象。
看上去还是比较晦涩,加上自己的理解就是:
有订阅者(StreamSubscription)
就一定会有生产者
,不然就没意义了,订阅者
订阅了就会收到东西
(可能是正确的,有可能是错误的),可以针对这些东西做处理
,当然也可以暂停订阅
、恢复订阅
等,
onData()——处理接收到的正确的数据
onError()——处理接收到的错误
onDone()——当生产者不再生成数据(生产者调用close方法)时触发
isPaused——获取接收者状态,判断当前接收者是否暂停接收
pause()——暂停接收数据
resume()——恢复接收数据
cancel()——取消此订阅,不管生产者是否继续,将不再接收到信息
生产者(stream)
可以生成东西,也可生成错误等;
listen()——返回订阅者对象,和订阅者产生关联的主要模式
add()——产生正确的数据
addError()——产生错误
isClosed——是否已经关闭
close()——关闭生产者(订阅者对象会触发onDone())
注:这两如何产生联系?
一般当调用stream
的listen
就会返回StreamSubscription
对象;
代码例子:
// 创建一个StreamController(生成数据)
final StreamController<int> _streamController = StreamController<int>();
// 声明一个StreamSubscription变量(订阅消费数据)
late final StreamSubscription<int> _subscription;
// 用于显示接收到的数据
List<int> _receivedData = [];
// 计时器,用于生成数据
Timer? _timer;
// 计数器
int _counter = 0;
@override
void initState() {
super.initState();
// 初始化StreamSubscription
_subscription = _streamController.stream.listen(
// // 当接收到新数据时的回调
// (data) {},
// // 错误处理回调
// onError: (error) {
// print('Stream错误: $error');
// },
// // 流完成时的回调
// onDone: () {
// print('Stream已完成(close)——触发 onDone');
// },
null, // onData、onError、onDone 单独实现时,这儿传null就行
// 设置是否在错误发生时取消订阅
cancelOnError: false,
);
_subscription.onData((data) {
setState(() {
_receivedData.add(data);
// 只保留最新的5个数据
if (_receivedData.length > 5) {
_receivedData.removeAt(0);
}
});
});
_subscription.onError((error) {
print('Stream错误: $error');
});
_subscription.onDone(() {
print('Stream已完成(close)——触发 onDone');
});
// 启动定时器,每秒向流中添加一个新数字
_startTimer();
}
// 启动定时器方法
void _startTimer() {
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
// 向流中添加数据
_streamController.add(_counter++);
});
}
// 暂停订阅
void _pauseSubscription() {
if (!_subscription.isPaused) {
_subscription.pause();
}
}
// 恢复订阅
void _resumeSubscription() {
if (_subscription.isPaused) {
_subscription.resume();
}
}
// 向流中添加错误
void _addError() {
_streamController.addError('这是一个测试错误');
}
// 关闭Stream
void _closeStream() {
// 停止定时器
_timer?.cancel();
_timer = null;
// 关闭StreamController,这会触发onDone回调
if (!_streamController.isClosed) {
_streamController.close();
}
}
@override
void dispose() {
// 取消定时器
_timer?.cancel();
// 先关闭StreamController
_streamController.close();
// 再取消流订阅
_subscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('StreamSubscription示例')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('接收到的最新数据:'),
const SizedBox(height: 10),
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(5),
),
child: Text(
_receivedData.isEmpty ? '尚未接收数据' : _receivedData.join(', '),
style: const TextStyle(fontSize: 16),
),
),
const SizedBox(height: 30),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _pauseSubscription,
child: const Text('暂停订阅'),
),
ElevatedButton(
onPressed: _resumeSubscription,
child: const Text('恢复订阅'),
),
ElevatedButton(onPressed: _addError, child: const Text('添加错误')),
ElevatedButton(
onPressed: _closeStream,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
child: const Text('关闭Stream (触发onDone)'),
),
],
),
const SizedBox(height: 50),
const Text(
'StreamSubscription说明:',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
const Text(
'1. StreamSubscription用于订阅数据流(Stream)\n'
'2. 通过listen()方法创建订阅并处理数据\n'
'3. 可以暂停(pause)和恢复(resume)数据接收\n'
'4. 必须在不需要时取消(cancel)订阅以防止内存泄漏\n'
'5. 在本例中,定时器每秒产生一个数字并发送到流中\n'
'6. 使用上方按钮可以控制数据流的接收',
style: TextStyle(fontSize: 14),
),
],
),
),
);
}
代码效果:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。