You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter使用socket_io_client时如何读取StreamSocket的全部数据

问题原因
  • 存储变量为单值类型,每次收到新消息都会直接覆盖旧值,自然只能保留最后一条数据
  • 给message事件注册了两个重复监听,逻辑冗余
  • 往Stream里添加数据的代码存在语法错误,没有把收到的服务端数据传入addResponse方法,导致Stream本身没有收到预期数据
  • StreamBuilder没有正确消费Stream流数据,而是直接绑定了会被覆盖的全局单值变量
解决方案
  1. 将单值存储变量修改为列表类型,每次收到新数据时追加到列表中而非直接覆盖
  2. 合并重复的消息监听逻辑,修正往Stream塞数据的语法错误
  3. StreamBuilder直接消费流数据,绑定累计存储的列表展示所有内容
  4. 将全局的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 17:36:03