Flutter中使用Bloc实现Firebase OTP认证时遇状态更新错误
问题解决指南
错误原因
你遇到的问题核心是:Firebase verifyPhoneNumber的回调函数(如codeSent、verificationFailed)会在Bloc事件处理函数_verifyPhoneNumber执行完毕后才触发,此时Bloc的emit已经被标记为完成状态,再调用emit就会违反Bloc的状态更新规则,触发你看到的错误提示。
一、修复Bloc事件处理中的emit问题
修改_verifyPhoneNumber方法,在每个回调里调用emit前先检查emit.isDone,确保当前事件处理上下文仍有效:
void _verifyPhoneNumber(LoginInSubmittedEvent event, Emitter<SignInState> emit) async { String phone = "+91${event.phoneNumber}"; try { emit(SignInLoadingState()); await firebaseAuth.verifyPhoneNumber( phoneNumber: phone, verificationCompleted: (PhoneAuthCredential credential) { // 先确认emit未完成再更新状态 if (!emit.isDone) { emit(SignInCompletedState(credential)); } }, verificationFailed: (FirebaseAuthException e) { if (!emit.isDone) { emit(SignInErrorState(e.toString())); } }, codeSent: (String verificationId, int? resendToken) { if (!emit.isDone) { emit(SignInValidateState(verificationId, resendToken)); } }, codeAutoRetrievalTimeout: (String verificationId) { if (!emit.isDone) { emit(SignInTimeoutState(verificationId)); } }, ); } catch (e) { if (!emit.isDone) { emit(SignInErrorState(e.toString())); } } }
注:回调函数无需加async,去掉多余的异步标记可避免上下文冲突。
二、修复UI中状态检查的问题
你在按钮onPressed里同步检查state是无效的——Bloc状态更新是异步的,点击按钮后立即检查时,状态还未完成更新。正确做法是用BlocListener或BlocBuilder监听状态变化:
方案1:用BlocListener处理状态副作用(如打印日志、跳转页面)
BlocListener<SignInBloc, SignInState>( listener: (context, state) { if (state is SignInLoadingState) { debugPrint('Loading State'); } else if (state is SignInErrorState) { debugPrint('Error: ${state.errorMessage}'); } else if (state is SignInValidateState) { debugPrint('OTP SENT State'); // 此处可添加跳转到OTP输入页等逻辑 } else if (state is SignInTimeoutState) { debugPrint('TimeOut State'); } }, child: TextButton( onPressed: () { const phoneNumber = '3453453252'; BlocProvider.of<SignInBloc>(context).add(LoginInSubmittedEvent(phoneNumber)); }, child: Text( 'Get Otp', style: AppTextStyles.backNextBtnTextStyle, ), ), )
方案2:用BlocBuilder动态更新UI(如显示加载状态)
BlocBuilder<SignInBloc, SignInState>( builder: (context, state) { // 加载状态时显示进度指示器 if (state is SignInLoadingState) { return const CircularProgressIndicator(); } return TextButton( onPressed: () { const phoneNumber = '3453453252'; BlocProvider.of<SignInBloc>(context).add(LoginInSubmittedEvent(phoneNumber)); }, child: Text( 'Get Otp', style: AppTextStyles.backNextBtnTextStyle, ), ); }, )
内容的提问来源于stack exchange,提问作者Sunil Chaudhary
相关产品推荐
相关产品推荐

