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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 11:57:43