TabBarView 中具有 WebSockets 流的流生成器:错误状态:流已被侦听



我想在 TabBarView 中显示的 Widget 中收听 websocket 流:

import 'package:flutter/material.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
class RabitHouse extends StatefulWidget {
final channel = IOWebSocketChannel.connect('ws://echo.websocket.org');
@override
_RabitHouseState createState() => _RabitHouseState();
}
class _RabitHouseState extends State<RabitHouse> {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [
Tab(
icon: Icon(
Icons.adb,
),
),
Tab(
icon: Icon(
Icons.android,
)),
]),
),
body: TabBarView(children: [
Rabit(channel: widget.channel),
Rabit(channel: widget.channel),
]),
));
}
@override
void dispose() {
widget.channel.sink.close();
super.dispose();
}
}
class Rabit extends StatefulWidget {
final WebSocketChannel channel;
const Rabit({Key key, this.channel}) : super(key: key);
@override
_RabitState createState() => _RabitState();
}
class _RabitState extends State<Rabit> {
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: widget.channel.stream,
builder: (context, snapshot) => Text('pew pew'),
);
}
}

但是,当我更改选项卡时,我得到一个异常:

══════════════════════════════════════════════════════════════════

在构建 Rabit(状态:_RabitState#cd14b( 时抛出了以下 StateError: 错误状态:已收听流。

我错过了什么?

默认情况下,Dart 中的流是单侦听器,这意味着如果您尝试多次收听它们,它们将引发错误。如果要在多个位置收听流,则需要将其转换为广播流:

class _RabitHouseState extends State<RabitHouse> {
Stream broadcastStream;
@override
void initState() {
broadcastStream = widget.channel.stream.asBroadcastStream();
super.initState();
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [
Tab(
icon: Icon(
Icons.adb,
),
),
Tab(
icon: Icon(
Icons.android,
)),
]),
),
body: TabBarView(children: [
Rabit(stream: broadcastStream),
Rabit(stream: broadcastStream),
]),
));
}
@override
void dispose() {
widget.channel.sink.close();
super.dispose();
}
}
class Rabit extends StatefulWidget {
final Stream stream;
const Rabit({Key key, this.stream}) : super(key: key);
@override
_RabitState createState() => _RabitState();
}
class _RabitState extends State<Rabit> {
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: widget.stream,
builder: (context, snapshot) => Text('pew pew'),
);
}
}

如果您"订阅"两次,则可以收听同一流。创建两个 WebSocket 通道,然后asBroadcastStream()收听它们:

class RabitHouse extends StatefulWidget {
final channel1 = IOWebSocketChannel.connect('ws://echo.websocket.org');
final channel2 = IOWebSocketChannel.connect('ws://echo.websocket.org');
@override
_RabitHouseState createState() => _RabitHouseState();
}
class _RabitHouseState extends State<RabitHouse> {
Stream stream1;
Stream stream2;
@override
void initState() {
stream1  = widget.channel1.stream.asBroadcastStream();
stream2  = widget.channel2.stream.asBroadcastStream();
super.initState();
}
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(tabs: [
Tab(
icon: Icon(
Icons.adb,
),
),
Tab(
icon: Icon(
Icons.android,
)
),
]),
),
body: TabBarView(children: [
Rabit(stream: stream1),
Rabit(stream: stream2),
]),
)
);
}
@override
void dispose() {
widget.channel1.sink.close();
widget.channel2.sink.close();
super.dispose();
}
}
class Rabit extends StatefulWidget {
final Stream stream;
const Rabit({Key key, this.stream}) : super(key: key);
@override
_RabitState createState() => _RabitState();
}
class _RabitState extends State<Rabit> {
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: widget.stream,
builder: (context, snapshot) => Text('pew pew'),
);
}
}

如果您想了解有关流的更多信息,请从 dart.dev

有两种流

单个订阅流最常见的流类型包含 作为更大整体一部分的事件序列。事件需要 以正确的顺序交付,并且不会错过任何一个。这 是您在读取文件或接收网络时获得的流类型 请求。

这样的流只能听一次。稍后再听 可能意味着错过初始事件,然后是其余的 流毫无意义。当您开始收听时,数据将是 以块的形式获取和提供。

广播流 另一种流适用于个人 一次可以处理一个的消息。这种流可以是 例如,用于浏览器中的鼠标事件。

您可以随时开始收听这样的流,然后得到 侦听时触发的事件。多个侦听器可以 同时收听,以后可以再听 取消以前的订阅。

相关内容