Flutter使用socket_io_client时如何读取StreamSocket的全部数据
问题原因
- 存储变量为单值类型,每次收到新消息都会直接覆盖旧值,自然只能保留最后一条数据
- 给
message事件注册了两个重复监听,逻辑冗余 - 往Stream里添加数据的代码存在语法错误,没有把收到的服务端数据传入
addResponse方法,导致Stream本身没有收到预期数据 - StreamBuilder没有正确消费Stream流数据,而是直接绑定了会被覆盖的全局单值变量
解决方案
- 将单值存储变量修改为列表类型,每次收到新数据时追加到列表中而非直接覆盖
- 合并重复的消息监听逻辑,修正往Stream塞数据的语法错误
- StreamBuilder直接消费流数据,绑定累计存储的列表展示所有内容
- 将全局的StreamSocket、存储变量移入State类中管理,页面销毁时主动释放资源,避免内存泄漏
关键修改点说明
- 存储变量修改:把
var datiDaServer;改为List<String> datiDaServer = []; - 消息监听修正:
// 原来的两个重复监听合并为一个 socket.on('message', (data) { String msg = data.toString(); print('收到新消息:$msg,消息长度:${msg.length}'); // 追加数据到列表而不是覆盖 datiDaServer.add(msg); // 把消息传入Stream,注意要带参数 streamSocket.addResponse(msg); // 打印当前所有累计数据 print('全部历史消息:$datiDaServer'); });
- StreamBuilder展示逻辑修改,直接展示累计的所有消息:
StreamBuilder( stream: streamSocket.getResponse, builder: (BuildContext context, AsyncSnapshot<String> snapshot) { return Expanded( child: ListView.builder( itemCount: datiDaServer.length, itemBuilder: (context, index) => Text(datiDaServer[index]), ), ); }, )
完整修改后代码
import 'package:flutter/material.dart'; import 'package:vincenzakart/widget/navigationdrawerwidget.dart'; import 'package:socket_io_client/socket_io_client.dart' as IO; import 'dart:async'; import 'dart:io'; class PilotiPage extends StatefulWidget { const PilotiPage({Key? key}) : super(key: key); @override PilotiPageState createState() => PilotiPageState(); } class PilotiPageState extends State<PilotiPage> { // 把变量移入State内部管理,避免全局污染 late StreamSocket streamSocket; List<String> datiDaServer = []; late IO.Socket socket; @override void initState() { super.initState(); streamSocket = StreamSocket(); initSocket(); } @override void dispose() { // 页面销毁时释放资源 streamSocket.dispose(); socket.disconnect(); socket.dispose(); super.dispose(); } void initSocket() { connectAndListen(); } @override Widget build(BuildContext context) => Scaffold( drawer: const NavigationDrawerWidget(), appBar: AppBar( title: const Text('Piloti'), centerTitle: true, backgroundColor: Colors.black12, ), body: Container( child: StreamBuilder( stream: streamSocket.getResponse, builder: (BuildContext context, AsyncSnapshot<String> snapshot) { // 列表展示所有历史消息 return ListView.builder( padding: const EdgeInsets.all(16), itemCount: datiDaServer.length, itemBuilder: (context, index) => Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Text('消息${index+1}:${datiDaServer[index]}'), ), ); }, ), ), ); void connectAndListen() { socket = IO.io('http://192.168.110.204:3999', IO.OptionBuilder().setTransports(['websocket']).build()); socket.connect(); socket.onConnect((_) { print('connect socket.io'); print(socket.id); }); // 合并消息监听逻辑 socket.on('message', (data) { String msg = data.toString(); print('收到消息:$msg'); print('消息长度:${msg.length}'); // 追加数据到列表 datiDaServer.add(msg); // 传入数据到Stream streamSocket.addResponse(msg); // 打印所有累计数据 print('当前全部消息:$datiDaServer'); }); socket.onDisconnect((_) => print('disconnect')); } } // Stream 工具类 class StreamSocket { final _socketResponse = StreamController<String>(); void Function(String) get addResponse => _socketResponse.sink.add; Stream<String> get getResponse => _socketResponse.stream; void dispose() { _socketResponse.close(); } }
打印StreamSocket全部内容的方法
如果你需要在任意位置获取所有Stream收到的内容,直接读取datiDaServer列表即可,列表中存储了连接建立后所有收到的历史消息。
内容的提问来源于stack exchange,提问作者Alessandro Buscema
相关产品推荐
相关产品推荐

