Bloc: Synchronize Events in BLoCs

Created on 19 Feb 2020  路  4Comments  路  Source: felangel/bloc

Description

Currently the events dispatched to the bloc are processed synchronously in the order which the events were added.

But I think the events have to be processed asynchronously.

Reproducing the Error

  • BLoC file
class RootBloc extends Bloc<String, String> {
  // Events
  static const DELAY_1 = 'DELAY_1';
  static const DELAY_3 = 'DELAY_3';
  static const DELAY_5 = 'DELAY_5';

  // States
  static const NONE = '';
  static const STATE_1 = 'STATE_1';
  static const STATE_3 = 'STATE_3';
  static const STATE_5 = 'STATE_5';

  @override
  String get initialState => NONE;

  @override
  Stream<String> mapEventToState(String event) async* {
    switch (event) {
      case DELAY_1:
        await Future.delayed(Duration(seconds: 1));
        yield STATE_1;
        break;
      case DELAY_3:
        await Future.delayed(Duration(seconds: 3));
        yield STATE_3;
        break;
      case DELAY_5:
        await Future.delayed(Duration(seconds: 5));
        yield STATE_5;
        break;
    }
  }
}
  • Dispatching events
// List/Column
children: <Widget>[
  BlocBuilder<RootBloc, String>(
    condition: (pre, current) => pre != current,
    builder: (context, state) {
      print("State Changed to: $state");
      return Text(state);
    },
  ),
  FlatButton(
    onPressed: () {
      print("Sending actions");
      bloc.add(RootBloc.DELAY_5);
      bloc.add(RootBloc.DELAY_3);
      bloc.add(RootBloc.DELAY_1);
    },
    child: Text("Send Actions"),
  ),
],

Current output

The whole process takes 9 seconds (5+3+1) to complete.

I/flutter (16094): Sending actions
I/flutter (16094): State Changed to: STATE_5
I/flutter (16094): State Changed to: STATE_3
I/flutter (16094): State Changed to: STATE_1

Expected behavior

I think this should take only 5 seconds to complete and the output should be as follows.

I/flutter (16094): Sending actions
I/flutter (16094): State Changed to: STATE_1
I/flutter (16094): State Changed to: STATE_3
I/flutter (16094): State Changed to: STATE_5

Hope you can understand my concern..

Thank You !!

bloc question

Most helpful comment

Thank you for the answer. :hugs:
I forgot to look in rxdart.. :unamused:

All 4 comments

Hi @Ramesh-X 馃憢
Thanks for opening an issue!

By default bloc handles events in the order they were added but you can override that behavior by overriding transformEvents.

I believe in your case you want to use flatMap so you can just add

@override
  Stream<String> transformEvents(
    Stream<String> events,
    Stream<String> Function(String) next,
  ) {
    return events.flatMap(next);
  }

And it should work as you expect.

Full Example:

import 'package:bloc/bloc.dart';
import 'package:rxdart/rxdart.dart';

class RootBloc extends Bloc<String, String> {
  // Events
  static const DELAY_1 = 'DELAY_1';
  static const DELAY_3 = 'DELAY_3';
  static const DELAY_5 = 'DELAY_5';

  // States
  static const NONE = '';
  static const STATE_1 = 'STATE_1';
  static const STATE_3 = 'STATE_3';
  static const STATE_5 = 'STATE_5';

  @override
  String get initialState => NONE;

  @override
  Stream<String> transformEvents(
    Stream<String> events,
    Stream<String> Function(String) next,
  ) {
    return events.flatMap(next);
  }

  @override
  void onTransition(Transition<String, String> transition) {
    super.onTransition(transition);
    print(transition);
  }

  @override
  Stream<String> mapEventToState(String event) async* {
    switch (event) {
      case DELAY_1:
        await Future.delayed(Duration(seconds: 1));
        yield STATE_1;
        break;
      case DELAY_3:
        await Future.delayed(Duration(seconds: 3));
        yield STATE_3;
        break;
      case DELAY_5:
        await Future.delayed(Duration(seconds: 5));
        yield STATE_5;
        break;
    }
  }
}

void main() {
  final bloc = RootBloc();
  bloc.add(RootBloc.DELAY_5);
  bloc.add(RootBloc.DELAY_3);
  bloc.add(RootBloc.DELAY_1);
}

Thank you for the answer. :hugs:
I forgot to look in rxdart.. :unamused:

With Flutter Bloc 6.0.1 ???

For Bloc 6.0.x also this works perfectly fine, but there is a small change in the function definition.

@override
Stream<Transition<EventType, StateType>> transformEvents(
  Stream<EventType> events,
  Stream<Transition<EventType, StateType>> Function(EventType) next,
) {
  return events.flatMap(next);
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

fvisticot picture fvisticot  路  31Comments

felangel picture felangel  路  32Comments

windinvip picture windinvip  路  39Comments

konstantin-doncov picture konstantin-doncov  路  30Comments

felangel picture felangel  路  35Comments