1

I'm trying to make a flutter app from a guide, to an updated version with newer BloC version but, i've trouble with the changes from the old version to the new version...

First, here is the error i got when i try to press "play" on my application at this stage:

Bad state: add(PlayerEvent) was called without a registered event handler. Make sure to register a handler via on((event, emit) {...})

For what i can understand, this is because mapEventToState is deprecated and from BloC 8.0.1, i've tried to make the change by myself but, i'm a beginner and i've trouble understanding how i should do it.

Here is my actual code who is now deprecated

class PlayBloc extends Bloc<PlayEvent, PlayState>{

  final PlayerControl radioPlayer;


  PlayBloc({required this.radioPlayer}) : assert(radioPlayer != null),super(isPausedState());

   @override //Déprécié
  PlayState get initialState => isPausedState();
 
  @override
  Stream<PlayState> mapEventToState(PlayEvent event) async* {
    if(event is PlayerEvent){
      yield isPlayingState();
      await radioPlayer.play(url: event.url);
    }
    else if(event is StopEvent){
      yield isPausedState();
      await radioPlayer.stop();
    }
  }
  
}

could explain to me how to transform this? I tried following the solution proposed here: Flutter bloc migration due to mapEventToState is not working

but I have trouble understanding the changes that have been made..

Thank You

EDIT : Tried again to change it into BloC 8.0 standard, still no luck, it throws an error on "on(mapEventToState)"

The argument type 'Future Function(PlayerEvent)' can't be assigned to the parameter type 'FutureOr Function(PlayerEvent, Emitter)'. (Documentation)

PlayBloc({required this.radioPlayer}) : assert(radioPlayer != null),super(isPausedState()){
    on<PlayerEvent>(mapEventToState);
  }

  //@override //Déprécié
  //PlayState get initialState => isPausedState();
  Future<void> mapEventToState (
      PlayerEvent event
      ) async {
    if (event is PlayerEvent) {
      if (state is isPausedState) {
        await radioPlayer.play(url: event.url);
        emit(isPlayingState());
      } else if (state is isPlayingState) {
        await radioPlayer.stop();
        emit(isPausedState());
      }
    }
  }
totalgaara
  • 11
  • 2

2 Answers2

1

What the error suggests is that you need to register an on(Event, Emitter) added to the constructor of your Bloc. The first step I would take is to migrate to a single function. This is what I would do:

  1. Add bloc_concurrency to pubspec.yml: This is important so that your new on(Event, Emitter) behaves exactly like your mapEventToState.
  2. Change PlayBloc to something like this:
class PlayBloc extends Bloc<PlayerEvent, PlayerState> {
  PlayBloc({required this.radioPlayer}) : assert(radioPlayer != null),super(isPausedState()){
    on<PlayerEvent>(
      mapEventToState,
      transformer: sequential(),
    );
  }

  //@override //Déprécié
  //PlayState get initialState => isPausedState();
  Future<void> mapEventToState (
      PlayerEvent event,
      Emitter<MyState> emit,
      ) async {
    if (event is PlayerEvent) {
      if (state is isPausedState) {
        await radioPlayer.play(url: event.url);
        emit(isPlayingState());
      } else if (state is isPlayingState) {
        await radioPlayer.stop();
        emit(isPausedState());
      }
    }
  }
}

Notice that mapEventToState now receives both the event and the emit. This last emitter is the function you will use to update the state of your Bloc.

For reference, here are a couple of posts by VeryGoodVentures about Bloc's new API and how to use concurrency. And then (shameless plug), here's a tutorial about Bloc 8.0 I wrote a while back.

Alejandro
  • 139
  • 6
0

Try bellow code. In latest version to update changes in UI from bloc you have to write emit instead of yeild and async instead of async*.

New method call like this

on((event, emit) async{
      
});
    

You can also call like this

on<className>((event, emit) async{
          
});

For reference I shared you one my bloc close.

class CovidBloc extends Bloc<CovidEvent, CovidState> {
  CovidBloc() : super(CovidInitial()) {
    final ApiRepository _apiRepository = ApiRepository();

    on<GetCovidList>((event, emit) async {
      try {
        print("Event2: $event");
        emit(CovidLoading());
        final mList = await _apiRepository.fetchCovidList();
        emit(CovidLoaded(mList));
        if (mList.error != null) {
          emit(CovidError(mList.error));
        }
      } on NetworkError {
        emit(const CovidError("Failed to fetch data. is your device online?"));
      }
    });
  }
}
Vishal Zaveri
  • 1,372
  • 2
  • 5
  • 12
  • Hi, thanks for your reply, i've tried it, if i use async instead of async* it throws me : Functions marked 'async' must have a return type assignable to 'Future'. (Documentation) Try fixing the return type of the function, or removing the modifier 'async' from the function body. if i use async * then it's fine but it still doesn't work unfortunatly, same error, i edited my first posts with some change regarding bloc 8.0.0 but still not luck either :/ – totalgaara Jul 02 '22 at 17:44
  • Yes now you have to listen this emit state in UI code using builder listener block. – Vishal Zaveri Jul 02 '22 at 17:54
  • You mean, on the "OnPressed" ? at this time it's like this : `context.read().add(PlayerEvent(url: _FunUrl));` – totalgaara Jul 02 '22 at 18:02
  • Yes it's event execution code. – Vishal Zaveri Jul 02 '22 at 18:10
  • Sorry, i'm not sure to understand what i'have to do ? :/ – totalgaara Jul 02 '22 at 18:26
  • Check my answer. I update it with example – Vishal Zaveri Jul 04 '22 at 14:16