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

Flutter使用flutter_bloc监听网络时SnackBar重复弹出4次求助

问题分析与解决方案

可能的原因

  • 重复状态触发:网络检测Stream在切换WiFi时可能连续多次发送相同状态事件(比如连续触发4次InternetDisconnected/InternetConnected),导致Cubit重复emit相同状态,BlocListener会对每一次emit做出响应。
  • 多实例监听:全局MainScaffold可能被多次实例化(比如路由嵌套、页面重建时重复创建),导致多个BlocListener同时监听InternetCubit,每个Listener都会触发一次SnackBar。
  • SnackBar叠加显示:前一次的SnackBar还未关闭,新的SnackBar就被触发,造成重复弹出的视觉效果。

具体解决步骤

1. 阻止Cubit重复emit相同状态

在InternetCubit的状态更新逻辑中,先判断当前状态是否与要发送的状态一致,避免重复emit:

class InternetCubit extends Cubit<InternetState> {
  final Connectivity connectivity;
  StreamSubscription? connectivitySubscription;

  InternetCubit({required this.connectivity}) : super(InternetLoading()) {
    monitorInternetConnection();
  }

  void monitorInternetConnection() {
    connectivitySubscription = connectivity.onConnectivityChanged.listen((result) {
      final newState = result == ConnectivityResult.none 
          ? InternetDisconnected() 
          : InternetConnected();
      // 仅当新状态与当前状态不同时才emit
      if (state != newState) {
        emit(newState);
      }
    });
  }

  @override
  Future<void> close() {
    connectivitySubscription?.cancel();
    return super.close();
  }
}

2. 让BlocListener仅响应状态变化

使用BlocListener的listenWhen参数,仅在旧状态与新状态不同时执行回调,同时确保SnackBar不会叠加:

class MainScaffold extends StatelessWidget {
  final Widget child;

  const MainScaffold({super.key, required this.child});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocListener<InternetCubit, InternetState>(
        // 仅当状态真正变化时触发监听
        listenWhen: (previous, current) => previous != current,
        listener: (context, state) {
          final messenger = ScaffoldMessenger.of(context);
          // 先移除当前可能存在的SnackBar,避免叠加
          messenger.removeCurrentSnackBar();
          if (state is InternetConnected) {
            messenger.showSnackBar(
              const SnackBar(content: Text('网络已连接')),
            );
          } else if (state is InternetDisconnected) {
            messenger.showSnackBar(
              const SnackBar(content: Text('网络已断开')),
            );
          }
        },
        child: child,
      ),
    );
  }
}

3. 确保MainScaffold全局唯一

检查路由配置,确保MainScaffold只作为最外层包裹组件,不要在每个页面中重复嵌套。例如:

MaterialApp(
  // 使用builder确保全局包裹所有页面
  builder: (context, child) => MainScaffold(child: child!),
  home: YourHomePage(),
);

通过以上步骤,就能避免SnackBar重复弹出的问题,确保状态变化时只显示一次对应的提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 02:55:34