简体   繁体   English

Flutter BLoC 事件竞争条件

[英]Flutter BLoC event race condition

Let's assume we have an app where user has a calendar where he can select a date for which he wants to get list of events.假设我们有一个应用程序,其中用户有一个日历,他可以在其中选择他想要获取事件列表的日期。 When user selects the date, we add an event CalendarSelectedDateChanged(DateTime) .当用户选择日期时,我们添加一个事件CalendarSelectedDateChanged(DateTime) Bloc component fetches data from API each time we receive such an event.每次我们收到这样的事件时,Bloc 组件都会从 API 获取数据。 We can imagine a situation when the response is received with different delay.我们可以想象以不同的延迟接收响应的情况。 This will produce the following scenario:这将产生以下场景:

  • User clicks date 1用户点击日期 1
  • API call is made with param date=1 API 调用是使用参数 date=1 进行的
  • State is set to loading状态设置为加载
  • User clicks date 2用户点击日期 2
  • State is set to loading状态设置为加载
  • Response from request date=2 is received收到来自请求 date=2 的响应
  • State is set to dataLoadSuccess(date=2)状态设置为 dataLoadSuccess(date=2)

Expected result is that we discard response from request date=1 here预期结果是我们在这里丢弃来自请求日期=1 的响应

  • Response from request date=1 is received收到来自请求日期=1 的响应
  • State is set to dataLoadSuccess(date=1)状态设置为 dataLoadSuccess(date=1)

How can we resolve such a race condition in the most elegant way (preferably for all BLoCs in the app at once)?我们如何以最优雅的方式解决这种竞争条件(最好同时解决应用程序中的所有 BLoC)?

Here's an exemplary code that will produce such an issue:这是一个会产生此类问题的示例代码:

class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {

  ExampleBloc()
      : super(ExampleDataLoadInProgress(DateTime.now())) {
    on<ExampleSelectedDateChanged>((event, emit) async {
      await _fetchData(event.date, emit);
    });
  }

  Future<void> _fetchData(DateTime selectedDate,
      Emitter<ExampleState> emit,) async {
    emit(ExampleDataLoadInProgress(selectedDateTime));
    try {
      final data = callAPI(selectedDateTime);
      emit(ExampleDataLoadSuccess(data, selectedDate));
    } on ApiException catch (e) {
      emit(ExampleDataLoadFailure(e, selectedDateTime));
    }
  }
}

By default all events are processed concurrently, you can change that behavior by setting a custom transformer:默认情况下,所有事件都是并发处理的,您可以通过设置自定义转换器来更改该行为:

You can read more about transformers here: https://pub.dev/packages/bloc_concurrency您可以在此处阅读有关转换器的更多信息: https : //pub.dev/packages/bloc_concurrency

class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {

  ExampleBloc()
      : super(ExampleDataLoadInProgress(DateTime.now())) {
    on<ExampleSelectedDateChanged>((event, emit) async {
      await _fetchData(event.date, emit);
    },
      transformer: restartable(), // ADD THIS LINE 
    );
  }

  Future<void> _fetchData(DateTime selectedDate,
      Emitter<ExampleState> emit,) async {
    emit(ExampleDataLoadInProgress(selectedDateTime));
    try {
      final data = callAPI(selectedDateTime);
      emit(ExampleDataLoadSuccess(data, selectedDate));
    } on ApiException catch (e) {
      emit(ExampleDataLoadFailure(e, selectedDateTime));
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM