【问题标题】:Issue after bloc migration - emit was called after an event handler completed normally块迁移后的问题 - 在事件处理程序正常完成后调用发出
【发布时间】:2022-01-02 03:51:40
【问题描述】:

在我迁移到最新版本的 bloc 后,我遇到了错误。 这是我迁移前的代码:

  SignInBloc(
      {required this.authenticationRepository,
      required this.userDataRepository})
      : super(SignInInitialState());

  SignInState get initialState => SignInInitialState();

  @override
  Stream<SignInState> mapEventToState(
    SignInEvent event,
  ) async* {
    if (event is SignInWithGoogle) {
      yield* mapSignInWithGoogleToState();
    }
    if (event is UpdateLastLoginEvent) {
      yield* mapUpdateLastLoginEventToState(event.uid, event.deviceID);
    }
  }

  Stream<SignInState> mapSignInWithGoogleToState() async* {
    yield SignInWithGoogleInProgressState();
    try {
      String res = await authenticationRepository.signInWithGoogle();
      yield SignInWithGoogleCompletedState(res);
    } catch (e) {
      print(e);
      yield SignInWithGoogleFailedState();
    }
  }

  Stream<SignInState> mapUpdateLastLoginEventToState(
      String uid, String deviceID) async* {
    yield UpdateLastLoginInProgressState();
    try {
      String? res = await userDataRepository.lastLogin(uid, deviceID);
      if (res != null) {
        yield UpdateLastLoginCompletedState(res);
      } else {
        yield UpdateLastLoginFailedState();
      }
    } catch (e) {
      print(e);
      yield UpdateLastLoginFailedState();
    }
  }

这是我在迁移后为代码所做的。虽然我不确定用 try 编码是否仍然是一件好事。

  SignInBloc(
      {required this.authenticationRepository,
      required this.userDataRepository})
      : super(SignInInitialState()) {
    on<SignInEvent>((event, emit) async {
      if (event is SignInWithGoogle) {
        mapSignInWithGoogleToState(emit);
      }
      if (event is UpdateLastLoginEvent) {
        mapUpdateLastLoginEventToState(emit, event.uid, event.deviceID);
      }
    });
  }

  Future<void> mapSignInWithGoogleToState(
    Emitter<SignInState> emit,
  ) async {
    emit(SignInWithGoogleInProgressState());
    try {
      String res = await authenticationRepository.signInWithGoogle();
      emit(SignInWithGoogleCompletedState(res));
    } catch (e) {
      print(e);
      emit(SignInWithGoogleFailedState());
    }
  }

  Future<void> mapUpdateLastLoginEventToState(
    Emitter<SignInState> emit,
    String uid,
    String deviceID,
  ) async {
    emit(UpdateLastLoginInProgressState());
    try {
      String? res = await userDataRepository.lastLogin(uid, deviceID);
      if (res != null) {
        emit(UpdateLastLoginCompletedState(res));
      } else {
        emit(UpdateLastLoginFailedState());
      }
    } catch (e) {
      print(e);
      emit(UpdateLastLoginFailedState());
    }
  }

这是我在日志中看到的内容,但如果我尝试实现 future.whenComplete,则会出现语法错误。请帮忙。谢谢!

I/flutter (18083): emit was called after an event handler completed normally.
I/flutter (18083): This is usually due to an unawaited future in an event handler.
I/flutter (18083): Please make sure to await all asynchronous operations with event handlers
I/flutter (18083): and use emit.isDone after asynchronous operations before calling emit() to
I/flutter (18083): ensure the event handler has not completed.
I/flutter (18083): 
I/flutter (18083):   **BAD**
I/flutter (18083):   on<Event>((event, emit) {
I/flutter (18083):     future.whenComplete(() => emit(...));
I/flutter (18083):   });
I/flutter (18083): 
I/flutter (18083):   **GOOD**
I/flutter (18083):   on<Event>((event, emit) async {
I/flutter (18083):     await future.whenComplete(() => emit(...));
I/flutter (18083):   });

【问题讨论】:

    标签: flutter bloc


    【解决方案1】:

    请尝试如下调整:

    SignInBloc(
          {required this.authenticationRepository,
          required this.userDataRepository})
          : super(SignInInitialState()) {
    
        // change this
        /*on<SignInEvent>((event, emit) {
          if (event is SignInWithGoogle) {
            mapSignInWithGoogleToState(emit);
          }
          if (event is UpdateLastLoginEvent) {
            mapUpdateLastLoginEventToState(emit, event.uid, event.deviceID);
          }
        });*/
    
        // to this
        on<SignInWithGoogle>(mapSignInWithGoogleToState);
        on<UpdateLastLoginEvent>(mapUpdateLastLoginEventToState);
      }
    

    同时调整你的功能:

    Future<void> mapSignInWithGoogleToState(
        SignInWithGoogle event,
        Emitter<SignInState> emit,
      ) async {
    ...
    }
    
    Future<void> mapUpdateLastLoginEventToState(
        UpdateLastLoginEvent event,
        Emitter<SignInState> emit,
      ) async {
    ...
    }
    
    

    使用 try/catch 方法还是可以的!

    如果有效,请告诉我。

    【讨论】:

    • 它适用于 mapSignInWithGoogleToState。但是对于 mapUpdateLastLoginEventToState 我将如何传递参数(event.uid 和 event.deviceID)?
    • 我现在明白了,event.uid 和 event.deviceID 可以在里面访问。非常感谢!
    • 是的,完全正确。您可以在方法中访问事件,并附上所有内容。不客气!
    猜你喜欢
    • 2022-01-10
    • 1970-01-01
    • 2021-12-02
    • 2022-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多