Flutter使用connectivity_plus+Bloc时启动无网自动显示SnackBar问题
问题根源
你当前的实现仅订阅了connectivity_plus的onConnectivityChanged流,这个流仅在网络状态发生切换时才会推送新事件,应用冷启动时的初始网络状态不会自动触发该流回调,因此启动时如果处于无网状态,不会触发无网提示。另外原有代码存在两个隐患:流订阅没有手动取消会造成内存泄漏,在Bloc监听回调中直接写UI组件(const SizedBox())属于无效代码。
修复方案
1. 修改ConnectedBloc逻辑
在Bloc初始化时主动查询一次当前网络状态,同时补全流订阅取消逻辑,抽离公共的状态判断方法:
class ConnectedBloc extends Bloc<ConnectedEvent, ConnectedState> { StreamSubscription? connectivitySubscription; ConnectedBloc() : super(ConnectedInitial()) { on<OnConnectedEvent>((event, emit) => emit(ConnectedSucess())); on<OnNotConnectedEvent>((event, emit) => emit(ConnectedFailure())); // 启动时主动检测初始网络状态 _checkInitialNetworkStatus(); // 监听后续网络状态变更 connectivitySubscription = Connectivity() .onConnectivityChanged .listen((ConnectivityResult result) { _handleNetworkChange(result); }); } Future<void> _checkInitialNetworkStatus() async { final initialResult = await Connectivity().checkConnectivity(); _handleNetworkChange(initialResult); } void _handleNetworkChange(ConnectivityResult result) { if (result == ConnectivityResult.wifi || result == ConnectivityResult.mobile) { add(OnConnectedEvent()); } else { add(OnNotConnectedEvent()); } } @override Future<void> close() { // 关闭Bloc时取消流订阅,避免内存泄漏 connectivitySubscription?.cancel(); return super.close(); } }
2. 调整BlocConsumer监听逻辑
移除listener中无效的UI组件代码,增加帧回调避免启动时上下文未挂载导致的SnackBar弹出报错,同时补全builder逻辑:
home: BlocConsumer<ConnectedBloc, ConnectedState>( listener: (context, state) { if (state is ConnectedSucess) { // 网络恢复时隐藏当前无网提示 ScaffoldMessenger.of(context).hideCurrentSnackBar(); } else if (state is ConnectedFailure) { // 等首帧渲染完成后再弹出提示,避免上下文未挂载异常 WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( duration: const Duration(seconds: 3), backgroundColor: Colors.transparent, elevation: 0, content: SystemMessagesSnackBar( message: 'No internet access. Check your connection', textButton: 'Refresh', onPressed: () => ScaffoldMessenger.of(context).hideCurrentSnackBar(), icon: SvgPicture.asset(constants.Assets.no_connection), ), ), ); }); } }, builder: (context, state) { // 替换为你原本的首页组件 return const HomePage(); }, ),
注意事项
- 如果你使用的是
connectivity_plus3.0.0及以上版本,checkConnectivity()的返回值和onConnectivityChanged的推送值都是List<ConnectivityResult>类型,只需要把判断逻辑改成「列表是否包含wifi/mobile类型」即可,核心逻辑不变。 - 该方案仅检测设备是否连接到网络,不验证网络是否真的可访问公网,如果需要判断真实可用网络,需要额外加一层公网连通性检测(比如请求一个固定的公网地址)。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

