Flutter Bloc调用异步函数时emit报错问题求助
问题解决:Flutter Bloc中emit报错的修复方案
错误原因分析
你的代码核心问题在于事件处理器中存在未被正确await的异步操作,导致事件处理器提前完成,后续的emit调用触发了!_isCompleted错误:
authResult.fold是同步方法,其内部的async回调返回的Future没有被等待,_onSubmitLogin方法会提前执行到末尾,导致事件处理器先完成,而后续whenComplete里的emit(LoginSuccess())是在处理器结束后调用的。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())); } } }
关键修改点
- 移除多余的emit逻辑:删掉
_onSubmitLogin中fold之后的if (emit.isDone) emit(LoginSuccess()),避免重复或非法emit。 - await fold内的异步操作:对
authResult.fold、configResult.fold、accessResult.fold添加await,确保事件处理器等待所有异步回调完成后才结束。 - 简化成功状态触发:在
await method1之后直接emit(LoginSuccess()),此时所有前置异步操作都已完成,且事件处理器仍处于运行状态,符合emit的调用要求。 - 修正错误参数:统一
LoginFailure的错误参数传递,确保错误信息正确。
内容的提问来源于stack exchange,提问作者GingerAle
相关产品推荐
相关产品推荐

