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

Flutter Riverpod+Socket.io:客户端重复接收消息问题求助

问题原因

你的问题核心是**build方法会被Flutter频繁调用**(比如状态更新、布局重绘、父组件刷新等场景),每次调用都会执行socket!.on("STD1"),这会重复注册事件监听器。当服务端发送一条消息时,所有已注册的监听器都会触发,导致同一条消息被多次处理。

解决方案

以下是两种可靠的修复方式,确保监听器只注册一次:

方案1:使用StatefulConsumer(推荐)

StatefulConsumer是Riverpod提供的结合了StatefulWidget和Consumer的组件,可以利用生命周期方法确保监听器只在初始化时注册一次,页面销毁时移除:

class HomePage extends StatefulConsumerWidget {
  const HomePage({super.key});

  @override
  ConsumerState<HomePage> createState() => _HomePageState();
}

class _HomePageState extends ConsumerState<HomePage> {
  @override
  void initState() {
    super.initState();
    // 仅在组件初始化时注册一次监听器
    socket!.on("STD1", (std) {
      final temp = Student(
        std['pid'],
        std['name'],
        std['id'],
        std['Nationality'],
        std['birthdate'],
        std['age'],
        std['location'],
        std['pnumber'],
        std['snumber'],
        std['image'],
        std['level'],
        std['registertime'],
        std['rname'],
        std['class'],
        [], [], [], [], []
      );
      ref.read(StudentProvider.notifier).addSTD(temp, '1');
    });
  }

  @override
  void dispose() {
    // 组件销毁时移除监听器,避免内存泄漏
    socket!.off("STD1");
    super.dispose();
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // 使用watch监听Provider变化,触发UI更新
    final students = ref.watch(StudentProvider);
    // 这里编写你的UI布局代码
    return Scaffold(
      body: // ... 你的页面内容
    );
  }
}

方案2:在ConsumerWidget中利用ref.listen实现单次注册

如果坚持使用无状态的ConsumerWidget,可以通过监听一个常量Provider来确保监听器只注册一次:

Widget build(BuildContext context, WidgetRef ref) {
  // 监听一个永远不会变化的常量Provider,fireImmediately确保首次build时执行
  ref.listen(
    Provider<bool>((_) => true),
    (previous, next) {
      socket!.on("STD1", (std) {
        final temp = Student(
          std['pid'],
          std['name'],
          std['id'],
          std['Nationality'],
          std['birthdate'],
          std['age'],
          std['location'],
          std['pnumber'],
          std['snumber'],
          std['image'],
          std['level'],
          std['registertime'],
          std['rname'],
          std['class'],
          [], [], [], [], []
        );
        ref.read(StudentProvider.notifier).addSTD(temp, '1');
      });
    },
    fireImmediately: true,
  );

  final students = ref.watch(StudentProvider);
  // 编写UI布局代码
  // ...
}
关键注意事项
  • 永远不要在build方法中注册事件监听器、发起网络请求或执行任何会产生副作用的操作,因为build会被频繁调用。
  • 务必在组件销毁时调用socket!.off("STD1")移除监听器,防止内存泄漏和无用的回调执行。

内容的提问来源于stack exchange,提问作者Star Jinx

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 22:14:59