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

Flutter Bloc实现手机号认证时emit状态失败的问题求助

Flutter Bloc 手机号认证emit失败问题

在Flutter应用中使用Bloc实现手机号认证功能,点击发送验证码按钮触发sendOtpEvent后,verifyOTPState无法正常被emit,出现错误:'emit was called after an event handler completed normally'。已尝试给codeSent回调添加async但无效。

相关代码

  1. Bloc事件处理代码:
on<sendOtpEvent>((event,emit)async{
         await _auth.verifyPhoneNumber(
          phoneNumber:event.number,
          verificationCompleted:(PhoneAuthCredential credentials){},
          verificationFailed: (FirebaseAuthException e) {
            emit(ErrorState(error: e.message.toString()));
          },
          codeSent: (String verificationId, int? forceResendingToken) async{
              emit(verifyOTPState(verificationID: verificationId));
              
            },
          codeAutoRetrievalTimeout: (String verificationId) {
          });
    });
  1. 错误日志:
E/flutter ( 7268): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:bloc/src/emitter.dart': Failed assertion: line 114 pos 7: '!_isCompleted': 
E/flutter ( 7268): 
E/flutter ( 7268): emit was called after an event handler completed normally.
E/flutter ( 7268): This is usually due to an unawaited future in an event handler.
E/flutter ( 7268): Please make sure to await all asynchronous operations with event handlers
E/flutter ( 7268): and use emit.isDone after asynchronous operations before calling emit() to
E/flutter ( 7268): ensure the event handler has not completed.
E/flutter ( 7268): 
E/flutter ( 7268):   **BAD**
E/flutter ( 7268):   on<Event>((event, emit) {
E/flutter ( 7268):     future.whenComplete(() => emit(...));
E/flutter ( 7268):   });
E/flutter ( 7268): 
E/flutter ( 7268):   **GOOD**
E/flutter ( 7268):   on<Event>((event, emit) async {
E/flutter ( 7268):     await future.whenComplete(() => emit(...));
E/flutter ( 7268):   });

解决方案

问题核心是verifyPhoneNumber的await不会等待codeSent等回调执行完毕,事件处理函数在verifyPhoneNumber返回后就已结束,后续codeSent中的emit操作就会触发错误。可以通过Completer手动等待回调完成:

修改后的Bloc事件处理代码:

on<sendOtpEvent>((event, emit) async {
  final completer = Completer<void>();
  
  await _auth.verifyPhoneNumber(
    phoneNumber: event.number,
    verificationCompleted: (PhoneAuthCredential credentials) {
      completer.complete();
    },
    verificationFailed: (FirebaseAuthException e) {
      emit(ErrorState(error: e.message.toString()));
      completer.complete();
    },
    codeSent: (String verificationId, int? forceResendingToken) {
      emit(verifyOTPState(verificationID: verificationId));
      completer.complete();
    },
    codeAutoRetrievalTimeout: (String verificationId) {
      completer.complete();
    },
  );
  
  // 等待任意回调执行完成后再结束事件处理
  await completer.future;
});

额外建议:遵循Dart命名规范,将事件类sendOtpEvent改为SendOtpEvent,状态类也保持大驼峰命名(如VerifyOtpState、ErrorState),提升代码可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:24:59