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

如何结合Bloc与Freezed包处理双API请求?求最优方案

解决方案分析

针对你的问题,有两种可行方案,具体选择取决于业务耦合度和未来扩展需求:


方案一:修复现有单Bloc的问题(不拆分)

当前报错的核心原因有两个:

  1. Bloc默认顺序处理事件,同时触发fetchObjects和fetchBalance时,第二个请求会等待第一个完成,若其中一个请求异常可能阻塞另一个;
  2. 状态设计为互斥类型,无法同时表示“对象加载中+余额加载中”这类并发状态,导致状态更新冲突。

修复步骤:

  1. 开启事件并发处理
    将事件注册改为分开处理,并启用concurrent: true,允许两个请求同时执行:

    ObjectsBloc({required this.objectsUseCase, required this.balanceUseCase})
        : super(const ObjectsState.initial()) {
      on<_FetchObjects>(_fetchObjects, concurrent: true);
      on<_FetchBalance>(_fetchBalance, concurrent: true);
    }
    
  2. 重构状态为组合式结构
    使用AsyncValue(flutter_bloc内置工具)统一管理每个数据的加载状态,让两个请求的状态独立更新:

    import 'package:bloc/bloc.dart';
    
    class ObjectsState with _$ObjectsState {
      const factory ObjectsState({
        required AsyncValue<ObjectsListResponse> objects,
        required AsyncValue<BalanceResponse> balance,
      }) = _ObjectsState;
    
      factory ObjectsState.initial() => ObjectsState(
            objects: const AsyncValue.loading(),
            balance: const AsyncValue.loading(),
          );
    }
    
  3. 更新事件处理逻辑
    在各自的请求方法中,只更新对应字段的状态:

    Future<void> _fetchObjects(Emitter<ObjectsState> emit) async {
      try {
        final objects = await objectsUseCase.execute();
        emit(state.copyWith(objects: AsyncValue.data(objects)));
      } catch (e) {
        emit(state.copyWith(objects: AsyncValue.error(e.toString())));
      }
    }
    
    Future<void> _fetchBalance(Emitter<ObjectsState> emit) async {
      try {
        final balance = await balanceUseCase.execute();
        emit(state.copyWith(balance: AsyncValue.data(balance)));
      } catch (e) {
        emit(state.copyWith(balance: AsyncValue.error(e.toString())));
      }
    }
    

这种方案适合对象和余额业务高度耦合(比如必须同时展示、关联操作)的场景,避免多Bloc的管理成本。


方案二:拆分独立Bloc(推荐未来扩展场景)

如果未来会新增更多独立请求,或者对象、余额的业务逻辑逐渐复杂,建议遵循单一职责原则,拆分为ObjectsBloc和BalanceBloc:

示例代码:

ObjectsBloc相关代码:

// ObjectsEvent
class ObjectsEvent with _$ObjectsEvent {
  const factory ObjectsEvent.fetchObjects() = _FetchObjects;
}

// ObjectsState
class ObjectsState with _$ObjectsState {
  const factory ObjectsState.initial() = _Initial;
  const factory ObjectsState.loading() = _Loading;
  const factory ObjectsState.loaded(ObjectsListResponse objects) = _Loaded;
  const factory ObjectsState.error(String message) = _Error;
}

// ObjectsBloc
class ObjectsBloc extends Bloc<ObjectsEvent, ObjectsState> {
  ObjectsBloc({required this.objectsUseCase}) : super(const ObjectsState.initial()) {
    on<_FetchObjects>(_fetchObjects);
  }

  final ObjectsUseCase objectsUseCase;

  Future<void> _fetchObjects(Emitter<ObjectsState> emit) async {
    emit(const ObjectsState.loading());
    try {
      final objects = await objectsUseCase.execute();
      emit(ObjectsState.loaded(objects));
    } catch (e) {
      emit(ObjectsState.error(e.toString()));
    }
  }
}

BalanceBloc相关代码:

// BalanceEvent
class BalanceEvent with _$BalanceEvent {
  const factory BalanceEvent.fetchBalance() = _FetchBalance;
}

// BalanceState
class BalanceState with _$BalanceState {
  const factory BalanceState.initial() = _Initial;
  const factory BalanceState.loading() = _Loading;
  const factory BalanceState.loaded(BalanceResponse balance) = _Loaded;
  const factory BalanceState.error(String message) = _Error;
}

// BalanceBloc
class BalanceBloc extends Bloc<BalanceEvent, BalanceState> {
  BalanceBloc({required this.balanceUseCase}) : super(const BalanceState.initial()) {
    on<_FetchBalance>(_fetchBalance);
  }

  final BalanceUseCase balanceUseCase;

  Future<void> _fetchBalance(Emitter<BalanceState> emit) async {
    emit(const BalanceState.loading());
    try {
      final balance = await balanceUseCase.execute();
      emit(BalanceState.loaded(balance));
    } catch (e) {
      emit(BalanceState.error(e.toString()));
    }
  }
}

优势:

  • 每个Bloc只负责单一业务,代码更清晰,易于维护和测试;
  • 未来新增请求时,直接新增对应Bloc即可,不会导致单个Bloc臃肿;
  • 单独调用某个请求时,直接触发对应Bloc的事件,逻辑更直观。

选择建议

  • 如果当前两个请求业务耦合度极高,且未来扩展有限,选方案一;
  • 如果未来会新增多个独立请求,或两个业务逻辑有各自的扩展方向,选方案二(长期来看更易维护)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:23:27