Flutter Bloc 使用 Timer 重新获取数据

zil*_*nas 2 dart flutter bloc flutter-bloc

我正在尝试在 Flutter Bloc 中创建一个计时器,以便在调用 DataFetchRequested 事件后每 30 秒获取一次数据。

\n\n
\nclass DataBloc extends Bloc<BlocEvent, BlocState> {\n  final Api _api;\n  Timer _timer;\n\n  DataBloc(this._api);\n\n  @override\n  BlocState get initialState => StateInitial();\n\n  @override\n  Stream<BlocState> mapEventToState(BlocEvent event) async* {\n    if (event is DataFetchRequested) {\n      _resetTimer((timer) => _fetchData());\n      yield* _fetchData();\n    }\n  }\n\n  Stream<BlocState> _fetchData() async* {\n    yield StateLoading();\n\n    try {\n      final result = await _api.fetch();\n      yield StateSuccess(result);\n    } catch (e) {\n      _timer.cancel();\n      yield StateFailure(e.toString());\n    }\n  }\n\n  _resetTimer(void Function(Timer) onCallback) {\n    _timer?.cancel();\n    _timer = Timer.periodic(Duration(seconds: 1), onCallback);\n  }\n\n  @override\n  Future<void> close() {\n    _timer?.cancel();\n    return super.close();\n  }\n}\n\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,以这种方式调用时,计时器不会执行任何操作。

\n\n

尝试改变

\n\n
_resetTimer((timer) => fetchFn);\n
Run Code Online (Sandbox Code Playgroud)\n\n

\n\n
yield* _resetTimer((timer) async* {\n  yield* fetchFn;\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

这导致了错误:

\n\n
Tried calling: listen(Closure: (Object) => void from Function \'_add@4048458\':., cancelOnError: false, onDone: Closure: () => void from Function \'_close@4048458\':., onError: Closure: (Object, StackTrace) => void from Function \'_addError@4048458\':.) occurred in bloc Instance of \'DataBloc\'.\n#0      Object.noSuchMethod  (dart:core-patch/object_patch.dart:53:5)\n#1      new _AddStreamState  (dart:async/stream_controller.dart:900:34)\n#2      new _StreamControllerAddStreamState  (dart:async/stream_controller.dart:952:9)\n#3      _StreamController.addStream  (dart:async/stream_controller.dart:571:13)\n#4      _AsyncStarStreamController.addStream  (dart:async-patch/async_patch.dart:206:37)\n#5      DataBloc.mapEventToState \npackage:app/\xe2\x80\xa6/data/DataBloc.dart:33\n<asynchronous suspension>\n#6      Bloc._bindEventsToStates.<anonymous closure> <\xe2\x80\xa6>\n
Run Code Online (Sandbox Code Playgroud)\n\n

是否可以使用 Bloc 中的 Timer 每 30 秒获取一次数据?

\n\n

尝试使用 Stream.periodic,但也失败了。

\n\n

我能够通过在演示文稿小部件中使用计时器并每 30 秒调用一次事件来实现我想要的目标,但我想将此逻辑从演示文稿小部件移动到 DataBloc - 这可能吗?

\n

Er1*_*Er1 8

我认为这应该有效;

class DataBloc extends Bloc<BlocEvent, BlocState> {
  final Api _api;
  StreamSubscription _periodicSubscription;

  DataBloc(this._api);

  @override
  BlocState get initialState => StateInitial();

  @override
  Stream<BlocState> mapEventToState(BlocEvent event) async* {
    if (event is DataFetchRequested) {
      yield StateLoading();
      if(_periodicSubscription == null) {
        _periodicSubscription ??=
            Stream.periodic(const Duration(seconds: 30), (x) => x).listen(
                    (_) => add(const FetchEvent()),
                onError: (error) =>
                    print("Do something with $error")
            );
      } else {
        _periodicSubscription.resume();
      }
    }
    if(event is FetchEvent){
      yield StateLoading();

      try {
        final result = await _api.fetch();
        yield StateSuccess(result);
      } catch (e) {
        _periodicSubscription.pause();
        yield StateFailure(e.toString());
      }
    }
  }

  @override
  Future<void> close() async {
    await _periodicSubscription?.cancel();
    _periodicSubscription = null;
    return super.close();
  }
}
Run Code Online (Sandbox Code Playgroud)

FetchEvent是您必须创建的新事件类。