1

I am using riverpod_generator in my Flutter app to generate a provider for a controller that I use. The controller is actually a Notifier.

I am wondering where is the correct place in the controller to set up the disposal of resources (in this case, a BehaviorSubject, and its stream's subscription.

Is it ok to do it in the build() method, as I have in the included code? Thanks

part "provider.g.dart";

final PlayersSearchFiltersValue _initialFilters = PlayersSearchFiltersValue(
  searchTerm: "",
);

@riverpod
class PlayersSearchAppController extends _$PlayersSearchAppController
    implements PlayersSearchController {
  late final PlayersService playersService =
      ref.read(playersAppServiceProvider);

  final BehaviorSubject<PlayersSearchFiltersValue> _filtersSubject =
      BehaviorSubject();
  late StreamSubscription<PlayersSearchFiltersValue> _filtersSubscription;
  StreamSink<PlayersSearchFiltersValue> get _filtersSink =>
      _filtersSubject.sink;

  @override
  AsyncValue<List<PlayerModel>> build() {
    _initializeController();
    return AsyncValue.data([]);
  }

  /// rest of the code

  void _initializeController() {
    _filtersSubscription = _filtersSubject.stream
        .debounceTime(Duration(milliseconds: 500))
        .listen((event) {
      _onSearchPlayers(event);
    });

    ref.onDispose(() async {
      await _filtersSubscription.cancel();
      await _filtersSubject.close();
    });
  }
}
Albina
  • 1,901
  • 3
  • 7
  • 19
user9661910
  • 29
  • 1
  • 2
  • read this Remi's tweet https://twitter.com/remi_rousselet/status/1493523352543285250. this is much better way than mixing Riverpod with RxDart style based on BehaviourSubjects – Nagual May 07 '23 at 08:51

1 Answers1

2

Yes, this will work great. The only thing, perhaps, is to define a separate _dispose method and allocate this piece of code to it in order to share responsibilities.


  @override
  AsyncValue<List<PlayerModel>> build() {
    _initializeController();
    _dispose();
    return AsyncValue.data([]);
  }

  void _dispose() {
    ref.onDispose(() async {
      await _filtersSubscription.cancel();
      await _filtersSubject.close();
    });
  }

  void _initializeController() {
    _filtersSubscription = _filtersSubject.stream
        .debounceTime(Duration(milliseconds: 500))
        .listen((event) {
      _onSearchPlayers(event);
    });
  }

Also, you should remember that generator by default creates providers that dispose their state (as with the dispose modifier). To change this behavior, use:

@Riverpod(keepAlive: true)
Ruble
  • 2,589
  • 3
  • 6
  • 29
  • Thanks @Ruble. Yeah, disposing in a separate method makes sense. I was mostly concerned that build method might be called multiple times during lifetime of the generated provider, and that would attach new listener on ref.dispose each time – user9661910 May 07 '23 at 07:55
  • 1
    yes, in the build method it is safe. It can also use `ref.watch` to watch and rebuild if necessary – Ruble May 07 '23 at 08:06