on<E extends Event> method

void on<E extends Event>(
  1. EventHandler<E, LocationState> handler, {
  2. EventTransformer<E>? transformer,
})
inherited

Register event handler for an event of type E. There should only ever be one event handler per event type E.

abstract class CounterEvent {}
class CounterIncrementPressed extends CounterEvent {}

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<CounterIncrementPressed>((event, emit) => emit(state + 1));
  }
}
  • A StateError will be thrown if there are multiple event handlers registered for the same type E.

By default, events will be processed concurrently.

See also:

  • EventTransformer to customize how events are processed.
  • package:bloc_concurrency for an opinionated set of event transformers.

Implementation

void on<E extends Event>(
  EventHandler<E, State> handler, {
  EventTransformer<E>? transformer,
}) {
  // ignore: prefer_asserts_with_message
  assert(() {
    final handlerExists = _handlers.any((handler) => handler.type == E);
    if (handlerExists) {
      throw StateError(
        'on<$E> was called multiple times. '
        'There should only be a single event handler per event type.',
      );
    }
    _handlers.add(_Handler(isType: (dynamic e) => e is E, type: E));
    return true;
  }());

  final subscription = (transformer ?? _eventTransformer)(
    _eventController.stream.where((event) => event is E).cast<E>(),
    (dynamic event) {
      void onEmit(State state) {
        if (isClosed) return;
        if (this.state == state && _emitted) return;
        onTransition(
          Transition(
            currentState: this.state,
            event: event as E,
            nextState: state,
          ),
        );
        emit(state);
      }

      final emitter = _Emitter(onEmit);
      final controller = StreamController<E>.broadcast(
        sync: true,
        onCancel: emitter.cancel,
      );

      Future<void> handleEvent() async {
        void onDone() {
          emitter.complete();
          _emitters.remove(emitter);
          if (!controller.isClosed) controller.close();
        }

        try {
          _emitters.add(emitter);
          await handler(event as E, emitter);
        } catch (error, stackTrace) {
          onError(error, stackTrace);
          rethrow;
        } finally {
          onDone();
        }
      }

      handleEvent();
      return controller.stream;
    },
  ).listen(null);
  _subscriptions.add(subscription);
}