Flutter - How to register abstract classes in get_it (service locator)

Viewed 279

I'm currently working on a simple project crypto_wallet. State management (BLoC) and Value Equality (freezed) creating CRUD operation of DB (Firebase) and in the watch method, I use StreamSubcription code is :

@injectable
class CoinWatcherBloc extends Bloc<CoinWatcherEvent, CoinWatcherState> {
  final ICoinRepository _repository;

  CoinWatcherBloc(this._repository, this._coinStreamSubscription) : 
 super(CoinWatcherState.initial());

  StreamSubscription<Either<CoinFailure, KtList<CoinEntity>>>? _coinStreamSubscription;

  @override
  Stream<CoinWatcherState> mapEventToState(CoinWatcherEvent event) async* {
    yield* event.map(
      watchCoin: (e) async* {
        yield CoinWatcherState.loadInProgress();
        await _coinStreamSubscription?.cancel();
        _coinStreamSubscription = _repository.watchCoin().listen(
              (failureOrSuccess) => add(
                CoinWatcherEvent.coinsReceived(failureOrSuccess),
              ),
            );
      },
      coinsReceived: (e) async* {
        yield e.failureOrCoin.fold(
          (f) => CoinWatcherState.loadFailure(f),
          (coin) => CoinWatcherState.loadSuccess(coin),
        );
      },
    );
  }
  @override
  Future<void> close() async {
    await _coinStreamSubscription?.cancel();
    return super.close();
  }
}

And at last I closed the stream. I inject all third party modules on @lazySingleton :

@module
abstract class FirebaseInjectableModule {
  @lazySingleton
  FirebaseAuth get firebaseAuth => FirebaseAuth.instance;
  @lazySingleton
  FirebaseFirestore get firebaseFirestore => FirebaseFirestore.instance;
  @lazySingleton
  GoogleSignIn get googleSignIn => GoogleSignIn();
}

Then It says :

Object/factory with  type StreamSubscription<Either<CoinFailure, KtList<CoinEntity>>> is not 
registered inside GetIt. 
(Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;
Did you forget to register it?)

If I also register this class like this.

@lazySingleton
StreamSubcription get streamSubcription => StreamSubcription();

Then it throws compile time error that abstract classes can't be instantiated like the all Third Party Classes I've registered. How to inject abstract classes? Is there any other way to do this? or I shouldn't use StreamSubcription something else? I'd be thankful <3 :)

2 Answers

You should not add this._coinStreamSubscription to your bloc's constructor. Remove it from the constructor, and declare it as a late final instance.

class CoinWatcherBloc extends Bloc<CoinWatcherEvent, CoinWatcherState> {
  final ICoinRepository _repository;

  CoinWatcherBloc(this._repository) : 
 super(CoinWatcherState.initial());

 late final StreamSubscription<Either<CoinFailure, KtList<CoinEntity>>>? _coinStreamSubscription;

get_it was trying to inject the abstract streamSubscription since it is in your constructor. And you do not need this. Also, if you look at it from a testing perspective, there is no need to mock the streamSubscription, you can instead mock the class that supplies data to it - which is the repository in this case

I generally just inject the implementation of the abstract class like @LazySingleton(as:AbstractClass).

Related