Flutter Bloc:如何更优雅地实现多Bloc协同调度
解决多个状态检查Bloc与Summary Bloc的通信问题
针对你的场景,核心目标是解耦Presentation层与Bloc之间的调度逻辑,让状态流转和结果汇总的逻辑下沉到Bloc层或Repository层,避免UI层承担过多业务调度职责。以下是两种最实用的实现方案:
方案一:让Summary Cubit直接依赖并监听其他检查Cubit
这种方式逻辑直接,依赖关系明确,无需引入额外层,适合简单的顺序检查场景。
重构思路
- 在
SummaryCubit初始化时,注入ConnectivityCheckCubit和BatteryCheckCubit的实例 - 订阅其他Cubit的状态流,在内部处理状态变化、触发后续检查、汇总结果
- Presentation层只需监听
SummaryCubit的状态,负责UI展示即可
代码示例
修改SummaryCubit
class SummaryCubit extends Cubit<SummaryState> { final ConnectivityCheckCubit _connectivityCubit; final BatteryCheckCubit _batteryCubit; late final StreamSubscription _connectivitySubscription; late final StreamSubscription _batterySubscription; // 构造函数注入依赖的Cubit SummaryCubit(this._connectivityCubit, this._batteryCubit) : super(SummaryInitial()) { _subscribeToConnectivity(); // 启动第一个检查流程 _connectivityCubit.checkConnectivity(); } // 监听网络检查状态 void _subscribeToConnectivity() { _connectivitySubscription = _connectivityCubit.stream.listen((state) { if (state is ConnectivityCheckSuccess) { emit(SummaryCheckConnectivity(status: SummaryStatus.success)); // 网络检查通过后,触发电池检查 _batteryCubit.checkBattery(); _subscribeToBattery(); } else if (state is ConnectivityCheckFailure) { emit(SummaryCheckConnectivity(status: SummaryStatus.failure)); // 网络失败时,可选择终止后续检查或继续 emit(SummaryCheckSuccess( connectivityStatus: SummaryStatus.failure, batteryLevel: null, )); } }); } // 监听电池检查状态 void _subscribeToBattery() { _batterySubscription = _batteryCubit.stream.listen((state) { if (state is BatteryCheckSuccess) { emit(SummaryCheckBattery(status: SummaryStatus.success, battery: state.battery)); // 汇总所有结果,完成检查流程 emit(SummaryCheckSuccess( connectivityStatus: SummaryStatus.success, batteryLevel: state.battery, )); } else if (state is BatteryCheckFailure) { emit(SummaryCheckBattery(status: SummaryStatus.failure)); emit(SummaryCheckSuccess( connectivityStatus: SummaryStatus.success, batteryLevel: null, )); } }); } // 记得取消订阅,避免内存泄漏 @override Future<void> close() { _connectivitySubscription.cancel(); _batterySubscription.cancel(); return super.close(); } }
重构Presentation层的Provider与Listener
// MultiBlocProvider注入时传递依赖 MultiBlocProvider( providers: [ BlocProvider(create: (context) => ConnectivityCheckCubit()), BlocProvider(create: (context) => BatteryCheckCubit()), BlocProvider( create: (context) => SummaryCubit( context.read<ConnectivityCheckCubit>(), context.read<BatteryCheckCubit>(), ), ), ], child: BlocListener<SummaryCubit, SummaryState>( listener: (context, state) { if (state is SummaryCheckConnectivity && state.status == SummaryStatus.failure) { // 显示网络警告 } else if (state is SummaryCheckBattery && state.status == SummaryStatus.failure) { // 显示电池警告 } else if (state is SummaryCheckSuccess) { // 显示汇总报告 } }, child: YourScreenWidget(), ), )
方案二:用Repository封装检查逻辑与调度(符合官方分层建议)
如果你的检查逻辑复杂、后续可能扩展更多检查项,推荐用Repository层封装所有业务逻辑,让Bloc只负责状态管理,进一步解耦。
重构思路
- 创建
CheckRepository,封装网络、电池等检查的具体实现,以及检查流程的调度 - Repository通过Stream向外暴露检查结果,
SummaryCubit订阅该Stream更新状态 - 单独的检查Cubit(如果需要)也依赖Repository,不再直接与其他Cubit通信
代码示例
定义CheckRepository与结果模型
// 统一的检查结果基类 abstract class CheckResult {} class ConnectivityCheckResult extends CheckResult { final bool isConnected; ConnectivityCheckResult({required this.isConnected}); } class BatteryCheckResult extends CheckResult { final int? level; BatteryCheckResult({required this.level}); } class FullCheckComplete extends CheckResult { final bool connectivity; final int? batteryLevel; FullCheckComplete({required this.connectivity, this.batteryLevel}); } class CheckRepository { final Connectivity _connectivity; final Battery _battery; final _resultsController = StreamController<CheckResult>.broadcast(); CheckRepository({ Connectivity? connectivity, Battery? battery, }) : _connectivity = connectivity ?? Connectivity(), _battery = battery ?? Battery(); // 对外暴露结果流 Stream<CheckResult> get checkResults => _resultsController.stream; // 执行完整检查流程 Future<void> runFullCheck() async { // 第一步:检查网络 final connectivityResult = await _connectivity.checkConnectivity(); final isConnected = connectivityResult != ConnectivityResult.none; _resultsController.add(ConnectivityCheckResult(isConnected: isConnected)); if (!isConnected) { _resultsController.add(FullCheckComplete(connectivity: isConnected, batteryLevel: null)); return; } // 第二步:检查电池 try { final batteryLevel = await _battery.batteryLevel; _resultsController.add(BatteryCheckResult(level: batteryLevel)); _resultsController.add(FullCheckComplete(connectivity: isConnected, batteryLevel: batteryLevel)); } catch (e) { _resultsController.add(BatteryCheckResult(level: null)); _resultsController.add(FullCheckComplete(connectivity: isConnected, batteryLevel: null)); } } void dispose() { _resultsController.close(); } }
修改SummaryCubit依赖Repository
class SummaryCubit extends Cubit<SummaryState> { final CheckRepository _checkRepository; late final StreamSubscription _resultSubscription; SummaryCubit(this._checkRepository) : super(SummaryInitial()) { _subscribeToResults(); // 启动检查流程 _checkRepository.runFullCheck(); } void _subscribeToResults() { _resultSubscription = _checkRepository.checkResults.listen((result) { if (result is ConnectivityCheckResult) { emit(SummaryCheckConnectivity( status: result.isConnected ? SummaryStatus.success : SummaryStatus.failure, )); } else if (result is BatteryCheckResult) { emit(SummaryCheckBattery( status: result.level != null ? SummaryStatus.success : SummaryStatus.failure, battery: result.level, )); } else if (result is FullCheckComplete) { emit(SummaryCheckSuccess( connectivityStatus: result.connectivity ? SummaryStatus.success : SummaryStatus.failure, batteryLevel: result.batteryLevel, )); } }); } @override Future<void> close() { _resultSubscription.cancel(); _checkRepository.dispose(); return super.close(); } }
Presentation层注入Provider
MultiBlocProvider( providers: [ // 注入Repository Provider(create: (context) => CheckRepository()), // SummaryCubit依赖Repository BlocProvider(create: (context) => SummaryCubit(context.read<CheckRepository>())), // 如果仍需要单独的检查Cubit,也依赖Repository BlocProvider(create: (context) => ConnectivityCheckCubit(context.read<CheckRepository>())), BlocProvider(create: (context) => BatteryCheckCubit(context.read<CheckRepository>())), ], child: BlocListener<SummaryCubit, SummaryState>( listener: (context, state) { // 仅处理UI展示逻辑 if (state is SummaryCheckConnectivity && state.status == SummaryStatus.failure) { // 显示网络警告 } else if (state is SummaryCheckBattery && state.status == SummaryStatus.failure) { // 显示电池警告 } else if (state is SummaryCheckSuccess) { // 显示汇总报告 } }, child: YourScreenWidget(), ), )
方案对比
- 方案一:实现简单,依赖关系清晰,适合检查流程固定、逻辑简单的场景,无需额外层。
- 方案二:完全遵循分层架构,业务逻辑封装在Repository,扩展性强,后续新增检查项只需修改Repository,Bloc和UI层无需大改。
两种方案都能彻底解决你当前Presentation层耦合度高的问题,可根据项目复杂度选择。
内容的提问来源于stack exchange,提问作者KT AT CBX
相关产品推荐
相关产品推荐

