sorry, this is not a issue or feature request, it's just a question
i have something like this in my bloc :
yield Loading();
final factors = []; // read some objects from db
await Future.forEach<FactorF>(factors, (factor) async* {
yield UpdateLoading(factor.id, true, false);
final result = await factor.send();
yield UpdateLoading(factor.id, false, result);
});
yield Finish();
i want send one by one factors and updating status, for using yield inside Future.forEach i must use async*, but when i using this instead of async, callback method not called
how can doing it ?
thanks
Hi @DJafari 馃憢
Thanks for opening an issue!
Regarding your question, you need to use yield* (yield-each) in order to push the new data onto the bloc state sink.
yield Loading();
final factors = []; // read some objects from db
yield* await Future.forEach<FactorF>(factors, (factor) async* {
yield UpdateLoading(factor.id, true, false);
final result = await factor.send();
yield UpdateLoading(factor.id, false, result);
});
yield Finish();
Hope that helps 馃憤
@felangel thanks man
when i use your solution, i get this exception :
NoSuchMethodError: The method 'listen' was called on null.
Receiver: null
Tried calling: listen(Closure: (Object) => void from Function '_add@8048458':., cancelOnError: false, onDone: Closure: () => void from Function '_close@8048458':., onError: Closure: (Object, StackTrace) => void from Function '_addError@8048458':.)
@felangel for saving your time
this is sample code for reproduced this exception :
import 'package:equatable/equatable.dart';
import 'package:bloc/bloc.dart';
abstract class MyState extends Equatable {
MyState([List props = const []]) : super(props);
}
class Init extends MyState {
@override
String toString() => "Init";
}
class Loading extends MyState {
@override
String toString() => "Loading";
}
class UpdateLoading extends MyState {
final int factorId;
final bool status;
final bool result;
UpdateLoading(this.factorId, this.status, this.result) : super([factorId, status, result]);
@override
String toString() => "UpdateLoading: { factorId: $factorId, status: $status, result: $result }";
}
class Finish extends MyState {
@override
String toString() => "Finish";
}
abstract class MyEvent extends Equatable {
MyEvent([List props = const []]) : super(props);
}
class TestEvent extends MyEvent {
@override
String toString() => "TestEvent";
}
class MyBloc extends Bloc<MyEvent, MyState> {
@override
MyState get initialState => Init();
@override
Stream<MyState> mapEventToState(MyEvent event) async* {
if(event is TestEvent) {
final factors = [1,2,3,4];
yield* await Future.forEach<int>(factors, (num) async* {
yield UpdateLoading(num, true, false);
await Future.delayed(Duration(seconds: 3));
yield UpdateLoading(num, false, false);
});
yield Finish();
}
}
}
@DJafari sorry for the delay but if you refactor mapEventToState to this it should work
@override
Stream<MyState> mapEventToState(MyEvent event) async* {
if (event is TestEvent) {
final factors = [1, 2, 3, 4];
await for (int num in Stream.fromIterable(factors)) {
yield UpdateLoading(num, true, false);
await Future.delayed(Duration(seconds: 3));
yield UpdateLoading(num, false, false);
}
yield Finish();
}
}
@felangel I met this issue recently, and await for is blocking bloc to receive new event. What I tried to achieve is to stop action immediately! Stop current uploading progress, but the bloc would not receive the event when await for is doing the jobs. Is there any way to slove this problem?
The only workaround I tried is to use listen instead of await for without blocking the code, and make a log event to dispatch in the callback instead of yield the log state in await for. I'm not sure If this is the only way to do so. 馃槩
Hi @Tokenyet 馃憢
If you want to stop processing the current event you can override transformEvents and use switchMap. Check out https://github.com/felangel/bloc/issues/517 馃憤
Most helpful comment
@DJafari sorry for the delay but if you refactor
mapEventToStateto this it should work