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

Flutter Bloc调用异步函数时emit报错问题求助

问题解决:Flutter Bloc中emit报错的修复方案

错误原因分析

你的代码核心问题在于事件处理器中存在未被正确await的异步操作,导致事件处理器提前完成,后续的emit调用触发了!_isCompleted错误:

  1. authResult.fold是同步方法,其内部的async回调返回的Future没有被等待,_onSubmitLogin方法会提前执行到末尾,导致事件处理器先完成,而后续whenComplete里的emit(LoginSuccess())是在处理器结束后调用的。
  2. method1、method2中的fold处理同样没有等待内部异步回调完成,可能导致这些方法提前结束,后续emit操作时机非法。

修复后的完整代码

class LoginBloc extends Bloc<LoginEvent, LoginState> {
  final UserRepository userRepository;

  LoginBloc({required this.userRepository}) : super(LoginInitial()) {
    on<SubmitLogin>(_onSubmitLogin);
  }

  Future<void> _onSubmitLogin(
    SubmitLogin event,
    Emitter<LoginState> emit,
  ) async {
    emit(LoginLoading());

    if (event.email.isNull || event.password.isNull) {
      emit(LoginFailure(status: AuthStatus.INVALID_CREDENTIALS));
      return;
    }

    try {
      final Either<AuthStatus, bool> authResult =
          await userRepository.authenticateUser(
        event.email,
        event.password,
      );

      // 用await等待fold内的所有异步逻辑完成,避免事件处理器提前结束
      await authResult.fold(
        (AuthStatus failure) async {
          emit(LoginFailure(status: failure));
        },
        (bool status) async {
          // 等待所有后续异步方法执行完毕
          await method1(event, emit);
          // 此时事件处理器仍在运行,emit合法
          emit(LoginSuccess());
        },
      );
    } catch (error) {
      emit(LoginFailure(error: error.toString()));
    }
  }

  Future<void> method1(
    SubmitLogin event,
    Emitter<LoginState> emit,
  ) async {
    try {
      final Either<ApiFailure, Para1> configResult =
          await userRepository.fetchConfigurations();

      await configResult.fold(
        (ApiFailure apiFailure) async {
          emit(LoginFailure(status: AuthStatus.SERVER_ERROR));
        },
        (Para1 para1) async {
          await method2(event, emit, para1);
        },
      );
    } catch (error) {
      emit(LoginFailure(error: error.toString()));
    }
  }

  Future<void> method2(
    SubmitLogin event,
    Emitter<LoginState> emit,
    Para1 para1,
  ) async {
    try {
      final Either<ApiFailure, Para2> accessResult =
          await userRepository.accessConfigurations();

      await accessResult.fold(
        (ApiFailure apiFailure) async {
          emit(LoginFailure(error: apiFailure.toString()));
        },
        (Para2 para2) async {
          await method3(event, emit, para1, para2);
        },
      );
    } catch (error) {
      emit(LoginFailure(error: error.toString()));
    }
  }

  Future<void> method3(
    SubmitLogin event,
    Emitter<LoginState> emit,
    Para1 para1,
    Para2 para2,
  ) async {
    try {
      await userRepository.saveUserData(
        para1,
        para2,
        event.email,
        event.password,
      );
    } catch (error) {
      emit(LoginFailure(error: error.toString()));
    }
  }
}

关键修改点

  1. 移除多余的emit逻辑:删掉_onSubmitLogin中fold之后的if (emit.isDone) emit(LoginSuccess()),避免重复或非法emit。
  2. await fold内的异步操作:对authResult.fold、configResult.fold、accessResult.fold添加await,确保事件处理器等待所有异步回调完成后才结束。
  3. 简化成功状态触发:在await method1之后直接emit(LoginSuccess()),此时所有前置异步操作都已完成,且事件处理器仍处于运行状态,符合emit的调用要求。
  4. 修正错误参数:统一LoginFailure的错误参数传递,确保错误信息正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:07:20