Bloc: How to call parallel request in flutter Bloc

Created on 5 Aug 2020  路  13Comments  路  Source: felangel/bloc

I am using BLOC in flutter.

As soon as BLOC instance is created I want to make to API calls.for that in the constructor I have added the following code.

class MyBloc extends Bloc<MyBlocEvent, MyBlocState> {

MyBloc() {
    _repository = MyAccountRepository();
    _myAccountList = List();
    add(API1CallEevent());
    add(API2CallEevent());
  }

and the event handling

```
@override
Stream mapEventToState(MyBlocEvent event) async* {
if (event is API1CallEevent) {

var ap1 =
await _repository.getAPI1();
----
----
}else if (event is API2CallEevent) {

var api2 =
await _repository.getAPI2();



}

}
```
The problem I am facing the API calls are not parallel after API1CallEevent complete API2CallEevent get execute...

is there any way to do it parallel.

question

Most helpful comment

The whole concept of bloc revolves around the idea of predictability. By default bloc processes events using asyncExpand operator which will ensure that incoming events will be processed in the order they were received.

If you want your actual events to be processed in parallel you can override the default event stream processing on this bloc:

  @override
  Stream<Transition<MyEvent, MyState>> transformEvents(
      Stream<MyEvent> events, transitionFn) {
    return events.flatMap(transitionFn);
  }

Alternatively you can change this behavior on certain events only.

All 13 comments

Hi @rahuldev91 馃憢

You can do that with await Future.wait([_repository.getAPI1(), _repository.getAPI2()]);

@RollyPeres @felangel the two API calls are independent...I want to execute two events in parallel.

I'm pretty sure you want to execute 2 requests in parallel and not 2 events.
You'll get back a List<Object> containing your independent API results.
Hope that clear things up for you 馃憤

@RollyPeres await Future.wait([_repository.getAPI1(), _repository.getAPI2()]); will return when api1 and api2 get complete.. callback is not parallel ..I want to perform these API calls independently .. for that I have created two different event

I am expacting add(API1CallEevent());add(API2CallEevent()); to call mapEventToState method in parallal

@rahuldev91 why do you want that? Then your bloc will be non-deterministic because the state will depend on the order in which the api calls were processed.

Either you should make the requests in parallel as @RollyPeres mentioned or you should make them in series as is currently the case when you use add.

The problem I am facing the API calls are not parallel after API1CallEevent complete API2CallEevent get execute...

is there any way to do it parallel.

You said you want the requests in parallel. So you can either do that with a single event like I suggested or use 2 different events and have the requests be executed sequentially.

If you care about parallelism then you should care about requests not events. Even if the 2 events would run in parallel that wouldn't matter at all if the actual API requests are not being executed in parallel. The parts you should care about are the actual requests since those might take longer.

@felangel @RollyPeres My concern is Future.wait([_repository.getAPI1(), _repository.getAPI2()]); its not true parallal work ..ultimalty result is going to come after both excutes.
for my case initially, I am showing skeleton loader in the list ..based on these API responses. I am replacing the data with loader .thats why I want to call these API independently in parallel.

@rahuldev91 it sounds like you are treating these as two different features and in that case I would recommend splitting the current bloc into two blocs/cubits.

@felangel but one bloc should allow the to do work parallel right .for this purpose I don't think creating new block is the solution ..if I have multiple APIs in the list then I need to create multiple blocks for all APIs.

@rahuldev91 no but if you have separate features for example two different loading indicators or skeleton loaders for different sections of the UI based on the two API calls then those should be represented as two different states.

On the other hand if it's a single skeleton loader and the list is aggregating the content from each of the requests then you can always process the requests in parallel like:

if (event is DataRequested) {
  yield state.copyWith(status: Status.loading);
  _repository.fetchDataFromA().then((data) => add(DataLoaded(data));
  _repository.fetchDataFromB().then((data) => add(DataLoaded(data));
} else if (event is DataLoaded) {
  yield state.copyWith(status: Status.success, data: List.from(state.data)..addAll(event.data));
}

An alternative option would be to have your repository expose a Stream and handle emitting the data from the two requests.

Hope that helps 馃憤

@felangel Thanks this will help me...
just for the curiosity why add to block not work in parallel ?

The whole concept of bloc revolves around the idea of predictability. By default bloc processes events using asyncExpand operator which will ensure that incoming events will be processed in the order they were received.

If you want your actual events to be processed in parallel you can override the default event stream processing on this bloc:

  @override
  Stream<Transition<MyEvent, MyState>> transformEvents(
      Stream<MyEvent> events, transitionFn) {
    return events.flatMap(transitionFn);
  }

Alternatively you can change this behavior on certain events only.

Was this page helpful?
0 / 5 - 0 ratings