'emit was called after an event handler completed normally' 定期计时器内的问题

'emit was called after an event handler completed normally' issue inside a periodic Timer

我正在使用 Flutter 和 flutter_bloc 制作一个应用程序,它定期向我的服务器发送 API 请求并请求数据。 在我使用 Timer 实现周期性功能之前,它一开始工作得很好,这是我的 bloc 文件:

class HomeBeehivesBloc extends Bloc<HomeBeehivesEvent, HomeBeehivesState> {
  HomeBeehivesBloc() : super(BeehivesInitial()) {
    on<LoadBeehives>((event, emit) => _onBeehivesLoaded(emit));
  }

  Future<void> _onBeehivesLoaded(Emitter<HomeBeehivesState> emit) async {
    emit(BeehivesLoading());

    final repository = BeehivesRepository();

    const duration = Duration(seconds: 5);
    Timer.periodic(duration, (timer) async {
      try {
        await repository.getHomeBeehives().then((beehives) async {
          emit(BeehivesLoadedSuccessfully(beehives: beehives));
        });
      } catch (exception) {
        log(exception.toString());
      }
    });
  }
}

但是我遇到了这个异常:

'package:bloc/src/emitter.dart': Failed assertion: line 114 pos 7: '!_isCompleted': 

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

我试过到处寻找解决方案,但老实说,这是我第一次使用新版本的 bloc 包(以前从未使用过 emit),我想要一些关于如何解决这个问题的建议。

附带问题:在那里实现周期性计时器是个好主意吗?因为我看到有人在前端实现它(例如有状态小部件),我也很乐意对此提出任何建议。

非常感谢!

您的代码不会等待 Timer.periodic 内的回调完成 - _onBeehivesLoaded 方法完成执行,因此当回调尝试发出新状态时 (BeehivesLoadedSuccessfully),你得到这个错误。

要解决此问题,您应该向 BLoC 添加一个新事件,然后像处理任何其他 BLoC 事件一样处理它,而不是在回调中发出新状态。

  1. 首先,创建一个新事件,例如HomeBeehivesLoaded:
class HomeBeehivesLoaded extends HomeBeehivesEvent {
  final List<Beehive> beehives; // <-- Not sure if Beehive is the right type, just an assumption

  const HomeBeehivesLoaded(this.beehives);
}
  1. 在您的 BLoC 中注册一个新的事件处理程序,它将根据加载的行为更新状态:
class HomeBeehivesBloc extends Bloc<HomeBeehivesEvent, HomeBeehivesState> {
  HomeBeehivesBloc() : super(BeehivesInitial()) {
    <...>
    on<HomeBeehivesLoaded>(_onHomeBeehivesLoaded);
  }
  
  void _onHomeBeehivesLoaded(HomeBeehivesLoaded event, Emitter<HomeBeehivesState> emit) {
    emit(BeehivesLoadedSuccessfully(beehives: event.beehives));
  }

  <...>
}
  1. Timer.periodic 回调中,从存储库获得响应后添加此事件,而不是发出状态:
class HomeBeehivesBloc extends Bloc<HomeBeehivesEvent, HomeBeehivesState> {
  <...>

  Future<void> _onBeehivesLoaded(Emitter<HomeBeehivesState> emit) async {
    <...>

    Timer.periodic(duration, (timer) async {
      try {
        await repository.getHomeBeehives().then((beehives) async {
          add(HomeBeehivesLoaded(beehives: beehives));
        });
      } catch (exception) {
        log(exception.toString());
      }
    });
  }
}