【问题标题】:Flutter bloc - emit was called after an event handler completed normallyFlutter bloc - 在事件处理程序正常完成后调用发出
【发布时间】:2022-02-17 16:09:47
【问题描述】:

我在 user_bloc.dart 中有这段代码:

UserBloc(this._userRepository, UserState userState) : super(userState) {
    on<RegisterUser>(_onRegisterUser);
  }

void _onRegisterUser(RegisterUser event, Emitter<UserState> emit) async {
    emit(UserRegistering());
    try {
      // detect when the user is registered
      FirebaseAuth.instance.authStateChanges().listen((User? user) async {
        if (state is UserRegistering && user != null) {
          // save user to db
          try {
            await _userRepository.addUpdateUserInfo(user.uid, userInfo);
          } catch (e) {
            emit(UserRegisteringError("Could not save user"));
          }
          emit(UserLoggedIn(user));
        }
      });
       ... call FirebaseAuth.instance.createUserWithEmailAndPassword

这是 _userRepository.addUpdateUserInfo:

Future<void> addUpdateUserInfo(String userId, UserInfo userInfo) async {
    try {
      var doc = usersInfo.doc(userId);
      await doc.set(
        {
          'first_name': userInfo.firstName,
          'last_name': userInfo.lastName,
          'email': userInfo.email
        },
        SetOptions(merge: true),
      );
    } catch (e) {
      print("Failed to add user: $e");
      throw Exception("Failed to add user");
    }
  }

emit(UserLoggedIn(user)); 被调用时,我得到这个错误:

Error: Assertion failed:
..\…\src\emitter.dart:114
!_isCompleted
"\n\n\nemit was called after an event handler completed normally.\nThis is usually due to an unawaited future in an event handler.\nPlease make sure to await all asynchronous operations with event handlers\nand use emit.isDone after asynchronous operations before calling emit() to\nensure the event handler has not completed.\n\n  **BAD**\n  on<Event>((event, emit) {\n    future.whenComplete(() => emit(...));\n  });\n\n  **GOOD**\n  on<Event>((event, emit) async {\n    await future.whenComplete(() => emit(...));\n  });\n"
    at Object.throw_ [as throw] (http://localhost:58334/dart_sdk.js:5067:11)
    at Object.assertFailed (http://localhost:58334/dart_sdk.js:4992:15)
at _Emitter.new.call (http://localhost:58334/packages/bloc/src/transition.dart.lib.js:765:40)
at user_bloc.UserBloc.new.<anonymous> (http://localhost:58334/packages/soli/blocs/bloc/user_bloc.dart.lib.js:90:20)
    at Generator.next (<anonymous>)
    at http://localhost:58334/dart_sdk.js:40571:33
    at _RootZone.runUnary (http://localhost:58334/dart_sdk.js:40441:59)
    at _FutureListener.thenAwait.handleValue (http://localhost:58334/dart_sdk.js:35363:29)
    at handleValueCallback (http://localhost:58334/dart_sdk.js:35931:49)
    at Function._propagateToListeners (http://localhost:58334/dart_sdk.js:35969:17)
    at _Future.new.[_completeWithValue] (http://localhost:58334/dart_sdk.js:35817:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:58334/dart_sdk.js:35838:35)
    at Object._microtaskLoop (http://localhost:58334/dart_sdk.js:40708:13)
    at _startMicrotaskLoop (http://localhost:58334/dart_sdk.js:40714:13)
    at http://localhost:58334/dart_sdk.js:36191:9
[2022-02-17T03:47:00.057Z]  @firebase/firestore:

收到错误后,如果我用其他用户重试,它可以正常工作。

【问题讨论】:

    标签: flutter dart async-await flutter-bloc


    【解决方案1】:

    这是预期的结果,因为 _onRegisterUser 方法已经完成执行,但 FirebaseAuth.instance.authStateChanges().listen(...) 内部的代码随后会尝试发出状态更改。

    在这种情况下您可以做什么,而不是在 FirebaseAuth 侦听器中发出新状态,您应该向 BLoC 添加新事件:

    if (state is UserRegistering && user != null) {
      // save user to db
      try {
        await _userRepository.addUpdateUserInfo(user.uid, userInfo);
      } catch (e) {
        add(RegistrationErrorEvent()); // Create this event
      }
        add(UserLoggedInEvent(user: user)); // Create this event
      }
    

    然后,您应该注册这些事件并处理逻辑:

    UserBloc(this._userRepository, UserState userState) : super(userState) {
      on<RegisterUser>(_onRegisterUser);
      on<RegistrationErrorEvent>((event, emit) => emit(UserRegisteringError("Could not save user")));
      on<UserLoggedInEvent>((event, emit) => emit(UserLoggedIn(event.user)));
    }
    

    另外,由于您使用的是流和listen 方法,请考虑使用StreamSubscription,以便在侦听状态更改后清理资源。

    Here 是来自 GitHub 上的 bloc 存储库的示例。

    【讨论】:

    • 我试试,谢谢。为什么在下面的时间我运行它没有错误?
    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 2022-12-15
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    相关资源
    最近更新 更多