Bloc: BlocDelegate exceptions

Created on 16 Apr 2019  ·  18Comments  ·  Source: felangel/bloc

What's wrong with it? I wrote a generic bloc and it works fine, it has states:

ModelEmpty
ModelLoading
ModelLoaded
ModelError

with first use, I create a bloc<A> and load Model A, it works fine
and then I create bloc<B> and start load model B, then I got this exception, bloc still works flawlessly but the state doesn't transit anymore.

Stacktrace

[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: Invalid argument(s)

0 _StringBase._interpolateSingle (dart:core-patch/string_patch.dart:823:7)

1 StringBuffer.write (dart:core-patch/string_buffer_patch.dart:64:24)

2 StringBuffer.writeAll (dart:core-patch/string_buffer_patch.dart:100:7)

3 IterableBase.iterableToFullString (dart:collection/iterable.dart:267:14)

4 ListBase.listToString (dart:collection/list.dart:29:20)

5 List.toString (dart:core-patch/growable_array.dart:364:33)

6 Equatable.toString

7 _StringBase._interpolate (dart:core-patch/string_patch.dart:840:19)

8 Transition.toString

9 _StringBase._interpolateSingle (dart:core-patch/string_patch.dart:821:17)

10 print (dart:core/print.dart:9:26)

11 MainBlocDelegate.onTransition

12 Bloc._bindStateSubject. (package:bloc/src/bloc.d<…>

question

Most helpful comment

Oh simple problem? Thank you very much

All 18 comments

Hi @hoaquo 👋
Thanks for opening an issue!

Is it possible for you to share a sample app with the problem you’re describing? Thanks!

That's big app, I can only extract bloc code here

class PagingModelBloc<T extends PagingModel> extends Bloc<PagingModelEvent, PagingModelState>
{
  final StoreRepository repository;

  PagingModelBloc({@required this.repository}) : assert(repository != null);

  @override
  PagingModelState get initialState => PagingModelEmpty();

  @override
  Stream<PagingModelState> mapEventToState(PagingModelEvent event) async* 
  {    
    if (event is FetchPagingModel) {
      yield PagingModelLoading();
      try {
        final PagingModel model = event.props[0];
        final int page = event.props[1];

        if (model is ModelA) {
          await repository.getModelA(model, page: page);
        }
        else if (model is ModelB) {
          await repository.getModelB(model, page: page);
        }
        else  {
          ....
        }

        yield PagingModelLoaded(pagingModel: model);
      } catch (_) {
        yield PagingModelError();
      }
    }
  }
}

In one screen I create a PagingModelBloc<ModelA> and get data very well.
One other screen I create PagingModelBloc<ModelB>, it also gets data very well, but at the initialize transition, ModelEmpty, I got above exception

@hoaquo thanks for the detail! Can you please share the implementation of MainBlocDelegate? Also, can you please provide the implementation of PagingModelEvent and PagingModelState? Thanks so much! 👍

There's nothing but just a print(transition) inside.

@hoaquo can you please provide the implementation of PagingModelEvent and PagingModelState?

Thank @felangel for fast reply. I think there's nothing special with implementation of Event and State classes

abstract class PagingModelEvent extends Equatable
{
  PagingModelEvent([List props = const []]) : super(props);
}

class FetchPagingModel<T extends PagingModel> extends PagingModelEvent
{
  final T pagingModel;
  final int page;

  FetchPagingModel({@required this.pagingModel, this.page}) :
    assert(pagingModel != null), super([pagingModel, page]); 
}
abstract class PagingModelState extends Equatable 
{
  PagingModelState([List props = const []]) : super(props);
}

class PagingModelEmpty extends PagingModelState {}

class PagingModelLoading extends PagingModelState {}

class PagingModelLoaded<T extends PagingModel> extends PagingModelState
{
  final T pagingModel;
  PagingModelLoaded({@required this.pagingModel}) : assert(pagingModel != null), super([pagingModel]);
}

class PagingModelError extends PagingModelState {}

Hmm it might be because you’re using generics with Equatable 🤔

Thanks for the additional info, it really helps! I’ll investigate and get back to you later today 👍

I don't know, first use with Bloc<ModelA> works fine but later call with Bloc<ModelB> doesn't work, then call again on Bloc<ModelA> works.

If possible, it would really help if you could put together a super simple app that illustrates the issue you’re having and share the link with me. It would be much easier to debug if I can reproduce the issue in an app on my own computer.

I sent email for you. :-)

Thanks I’ll have a look at the video.

Did you found something interesting, @felangel?

@hoaquo i'm actually looking right now haha.

@hoaquo I found the issue. It's because when the state is PagingModelLoaded, the onTransition method in your XenforumBlocDelegate calls print on the transition. This calls toString on PagingModel which throws an exception.

If I change your PagingModel override for toString() to this:

@override
String toString() => "PagingModel { title: $title }";

Then it works fine.

Oh simple problem? Thank you very much

But why the first call on other models have no problem?

@hoaquo it's because this model's toString was not overridden properly. I didn't look into it too much but my guess is your toString was either infinite looping or you were trying to print/access data that wasn't there so an exception was thrown. I noticed there was some sort of loop in the toString override and that was likely causing the problem.

Thank you very much for your great support @felangel

Was this page helpful?
0 / 5 - 0 ratings