如何在按钮点击时调用Bloc内的网络连接检测方法?
Bloc手动触发网络检测实现方案
Bloc的核心设计原则是所有状态变更必须通过事件(Event)驱动,不允许外部直接调用Bloc内部私有方法,你只需要新增对应事件、抽离公共检测逻辑即可实现复用,具体实现步骤如下:
1. 新增手动检测事件
先在你的ConnectedEvent定义中新增手动触发的事件类型:
// 原有事件保留,新增手动检测事件 abstract class ConnectedEvent {} class OnConnectedEvent extends ConnectedEvent {} class OnNotConnectedEvent extends ConnectedEvent {} class CheckNetworkManuallyEvent extends ConnectedEvent {} // 新增
2. 重构Bloc层逻辑,抽离可复用检测方法
你原有代码存在几个问题:定义的connection()监听方法从未调用、没有取消流订阅会引发内存泄漏、初始化时没有主动检测一次网络状态,重构后代码如下:
class ConnectedBloc extends Bloc<ConnectedEvent, ConnectedState> { StreamSubscription? connectivitySubscription; final Connectivity _connectivity = Connectivity(); ConnectedBloc() : super(ConnectedInitial()) { // 原有状态事件处理 on<OnConnectedEvent>((event, emit) => emit(ConnectedSucess())); on<OnNotConnectedEvent>((event, emit) => emit(ConnectedFailure())); // 注册手动检测事件的处理逻辑 on<CheckNetworkManuallyEvent>((event, emit) async { await _checkCurrentNetworkStatus(); }); // 初始化启动网络监听 _initConnectivityMonitor(); } // 抽离公共网络检测逻辑:自动监听、手动触发都复用该方法 Future<void> _checkCurrentNetworkStatus() async { final result = await _connectivity.checkConnectivity(); _emitStateByResult(result); } // 抽离网络结果对应状态更新逻辑 void _emitStateByResult(ConnectivityResult result) { if (result == ConnectivityResult.wifi || result == ConnectivityResult.mobile) { add(OnConnectedEvent()); } else { add(OnNotConnectedEvent()); } } // 初始化网络变化监听 void _initConnectivityMonitor() { // 初始化时先检测一次当前网络,避免刚进页面无状态 _checkCurrentNetworkStatus(); // 监听后续网络变化 connectivitySubscription = _connectivity.onConnectivityChanged.listen(_emitStateByResult); } // 重写close方法取消订阅,防止内存泄漏 @override Future<void> close() { connectivitySubscription?.cancel(); return super.close(); } }
3. 修改UI层按钮点击逻辑
在SnackBar的Refresh按钮点击时,向Bloc发送手动检测事件即可,不需要直接调用Bloc内部方法:
home: BlocConsumer<ConnectedBloc, ConnectedState>( listener: ((context, state) { if (state is ConnectedSucess) { // 网络恢复时自动隐藏SnackBar ScaffoldMessenger.of(context).hideCurrentSnackBar(); } else if (state is ConnectedFailure) { 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(); // 发送手动检测事件触发逻辑 context.read<ConnectedBloc>().add(CheckNetworkManuallyEvent()); }, icon: SvgPicture.asset(constants.Assets.no_connection), ), ), ); } }), builder: (context, state) { // 保留你原有的页面构建逻辑即可 return const Scaffold(); } )
注意:不要通过反射或者其他方式直接调用Bloc内部的私有方法,所有状态流转都走Event->Bloc->State的链路,才能保证状态可追踪、逻辑不混乱。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

