1
votes

I am using flutter_bloc library.

In the bloc, the mapEventToState method is an async* function which returns Stream<BlocState>. From this function I am calling other async* functions like this yield* _handleEvent(event)

In such method, I am calling some Future returns functions but in the Future then() function it wont let me call other yield* functions.

Here is an example:

Stream<BlocState> mapEventToState(BlocEvent event) async*{
     yield* _handlesEvent(event); //This calls to worker method 
}

Stream<BlocState> _handleEvent(BlocEvent event) async* {
   _repository.getData(event.id).then((response) async* { //Calling Future returned function
         yield* _processResult(response); //This won't work
     }).catchError((e)  async* {
         yield* _handleError(e);  //This won't work either
     });

   Response response = await _repository.getData(event.id); //This do works but I want to use it like above, is it possible?
   yield* _processResult(response); //This do works
}

The question is however, how to combine between Future and Stream in dart. I could use await _repository.getData which works. but then I won't catch the error.

3
use simple await instead of then: var response = await _repository.getData(event.id); yield* _processResult(response); - pskink
Thanks, I've mentioned this in my question, how do I catch the error like this? I wanted to use the built in catch error of the Future api. - Moti Bartov
use normal try-catch - what does not work that way? - pskink
Thanks, please refer my reply to @Candace below - Moti Bartov

3 Answers

1
votes

Try using a try-catch block instead. It works for me with await operations.

1
votes
  1. await is just syntactic sugar for .then(), and putting await in a try-catch block is syntactic sugar for using .catchError. Things that you can do one way can be done with the other.

  2. In your first version that uses .then()/.catchError(), your function doesn't return anything.

  3. Your callbacks won't work because you're using yield* in them, but you haven't specified the callbacks with sync* or async*. To avoid name collisions, the yield keyword requires them (in the same way that await requires a function use async or async*).

Here's a version that should work with .then() and .catchError():

Stream<BlocState> _handleEvent(BlocEvent event) async* {
  yield* await _repository.getData(event.id).then((response) async* {
    yield* _processResult(response);
  }).catchError((e) async* {
    yield* _handleError(e);
  });
}

Note that the callbacks don't need to use yield*; they could just return their Streams directly:

Stream<BlocState> _handleEvent(BlocEvent event) async* {
  yield* await _repository.getData(event.id).then((response) {
    return _processResult(response);
  }).catchError((e) {
    return _handleError(e);
  });
}

But (as everyone else has noted) using await instead of the Future API simplifies the whole thing (especially since we're already using await anyway):

Stream<BlocState> _handleEvent(BlocEvent event) async* {
  try 
    response = await _repository.getData(event.id);
    yield* _processResult(response);
  } catch (e) {
    yield* _handleError(e);
  }
}

See https://dartpad.dartlang.org/fc1ff92e461754bdb35b998e7fbb3406 for a runnable example.

0
votes

To handle errors in an async function, use try-catch:

try {
  Response response = await _repository.getData(event.id)
} catch (err) {
  print('Caught error: $err');
}