0

I am implementing an api that requires recursive calls to get all data. I have implemented a Bloc component that has a recursive transformer. However, it seems the transformer is keeps returning a null accumulator on the recursive call.

comments_bloc.dart

class CommentsBloc {
  final _repository = Repository();
  final _commentsFetcher = PublishSubject<int>();
  final _commentsOutput = BehaviorSubject<Map<int, Future<ItemModel>>>();

  // Stream Getters
  Observable<Map<int, Future<ItemModel>>> get itemWithComments =>
      _commentsOutput.stream;

  // Sink getters
  Function(int) get fetchItemWithComments => _commentsFetcher.sink.add;

  CommentsBloc() {
    _commentsFetcher.stream
        .transform(_commentsTransformer())
        .pipe(_commentsOutput);
  }

  _commentsTransformer() {
    return ScanStreamTransformer<int, Map<int, Future<ItemModel>>>(
      (cache, int id, index) {
        cache[id] = _repository.fetchItem(id);
        cache[id].then((ItemModel item) {
          item.kids.forEach((kidId) => fetchItemWithComments(kidId));
        });
      },
      <int, Future<ItemModel>>{},
    );
  }

  dispose() {
    _commentsFetcher.close();
    _commentsOutput.close();
  }
}

app.dart

return MaterialPageRoute(
  builder: (BuildContext context) {
    final itemId = int.parse(settings.name.replaceFirst('/', ''));
    final commentsBloc = CommentsProvider.of(context);

    commentsBloc.fetchItemWithComments(itemId);

    return NewsDetail(itemId: itemId);
  },
  );

Error

E/flutter (17142): [ERROR:flutter/shell/common/shell.cc(178)] Dart Error: Unhandled exception:
E/flutter (17142): NoSuchMethodError: The method '[]=' was called on null.
E/flutter (17142): Receiver: null
E/flutter (17142): Tried calling: []=(19307509, Instance of 'Future<ItemModel>')
E/flutter (17142): #0      _rootHandleUncaughtError.<anonymous closure> (dart:async/zone.dart:1112:29)
E/flutter (17142): #1      _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (17142): #2      _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)

The _commentsTransformer executes only the first instance the throws the error on cache[id] = _repository.fetchItem(id); ;

Isaac Obella
  • 2,613
  • 2
  • 16
  • 29

1 Answers1

1

Apparently cache is null. It is because you didn't return cache inside the transformer's accumulator function. You need to return it since it not an arrow function.

  _commentsTransformer() {
    return ScanStreamTransformer<int, Map<int, Future<ItemModel>>>(
      (cache, int id, index) {
        cache[id] = _repository.fetchItem(id);
        cache[id].then((ItemModel item) {
          item.kids.forEach((kidId) => fetchItemWithComments(kidId));
        });
        return cache;    //  <-- code fix here.
      },
      <int, Future<ItemModel>>{},
    );
  }
Amsakanna
  • 12,254
  • 8
  • 46
  • 58
  • I have done some debugging an realized its the cache that is null, Why would my `ScanStreamTransformer` be having a null cache value – Isaac Obella Mar 05 '19 at 14:31
  • @IsaacObella Looks like you're populating it with null. Did you debug what your `repository.fetchItem` method returns? – Amsakanna Mar 06 '19 at 03:35
  • Yes i did, when no data is found it returns a null, but even after adding a null check for it it still throws the error at `cache[id] = _repository.fetchItem(id);` claiming that cache is null. – Isaac Obella Mar 06 '19 at 05:18
  • @IsaacObella Silly me. I wonder what I was smoking lol. This entire time I knew that the `cache` is `null`. But I don't know why I wrote `cache[id]` in my answer and I don't know why I was focusing on handling nulls from `_repository.fetchItem(id)`. Nonetheless I think I found out the bug. You did not return `cache` inside the transformer's accumulator function since it is not an arrow function. – Amsakanna Mar 06 '19 at 07:58
  • If you were smoking then i was high, i couldn't even see the missing return statement. Thanks @Amsakanna. – Isaac Obella Mar 06 '19 at 08:58