我想听在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: 错误状态:流已被收听。
我想念什么?
答案 0 :(得分:1)
默认情况下,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'),
);
}
}
答案 1 :(得分:1)
如果您两次“订阅”同一流,则可以收听。创建两个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
有两种流
单个订阅流:最常见的流包含 是较大整体的一部分的事件序列。活动需要 以正确的顺序交付,并且没有丢失任何一个。这个 是您在阅读文件或接收网络时获得的信息流 请求。
这样的流只能被收听一次。稍后再听 可能意味着错过了最初的事件,然后剩下的 流没有意义。当您开始收听时,数据将 提取并分块提供。
广播流另一种流是针对个人的 一次可以处理的邮件。这种流可以是 例如,用于浏览器中的鼠标事件。
您可以随时开始收听此类视频流, 您收听时触发的事件。多个听众可以 同时听,之后您可以稍后再听 取消先前的订阅。