anonymous-dev
anonymous-dev

Reputation: 3489

How do I close a stream when my Get Controller is deleted from memory?

I am using the following package https://pub.dev/packages/get .

I have the following controller

class GroupController extends GetController{
  StreamController<GroupModel> _streamController = BehaviorSubject();
  Stream<GroupModel> get stream => _streamController.stream;

  GroupController(DatabaseService database, GroupModel group)
  {
   _streamController.addStream(database.groupStream(group));
  }

  @override
  void dispose(){
    print('dispose');
    _streamController.close();
    super.dispose();
  }
}

But when I call it the dispose is never called. I call it like this

GetBuilder<GroupController>(
        init: GroupController(database, _group),
        builder: (GroupController groupController) => StreamBuilder(
          stream: groupController.stream,
          builder: (BuildContext context, AsyncSnapshot<GroupModel> groupSnapshot) {

I want my controller's dispose method being called whenever the controller is removed from memory.

I noticed that the GetBuilder has a dispose callback. And it requires the state from a widget. So do I need to make the widget that holds the controller statefull? Or do I need to pass a new statefull widget that holds the state? The documentation is not all to clear on it. How do I call the dispose on my controller?

I noticed there is a console log whenever a controller get's deleted from memory, isn't there a callback so I can close the stream there? I would really like to avoid making the widget statefull tho.

Edit

class GroupController extends GetController{
  StreamController<GroupModel> _streamController = BehaviorSubject();
  Stream<GroupModel> get stream => _streamController.stream;

  GroupController(DatabaseService database, GroupModel group)
  {
   _streamController.addStream(database.groupStream(group));
  }

  @override
  void close(){
    print('log if close is invoked');
    _streamController.close();
    super.close();
  }
}

Generate the following log

I/flutter (23404): log if close is invoked 
I/flutter (23404): Close can't be called 
I/flutter (23404): [GET] GroupController deleted from memory

Somehow it error when trying to close the controller

Upvotes: 4

Views: 8090

Answers (2)

jonatas Borges
jonatas Borges

Reputation: 2227

If you insert a 'dispose' into your GetController, it will be ignored. This is because disposing is a method for discarding widgets in a StatefulWidget class, not for discarding controllers, not least because Get automatically and intelligently discards controllers to free resources when it is no longer needed. If you want to close streams, Get does it automatically, as long as you insert your streams into the onClose method.

class GroupController extends GetxController {
  StreamController<GroupModel> _streamController = BehaviorSubject();
  Stream<GroupModel> get stream => _streamController.stream;

  GroupController(DatabaseService database, GroupModel group);
  
  @override
  void onInit() {
    _streamController.addStream(database.groupStream(group));
    super.onInit();
  }

  // this
  @override
  void onClose() {
    print('dispose');
    _streamController.close();
    super.onClose();
  }
}

If you are using an old version of Get, you can use the same close and close method manually:

GetBuilder<GroupController>(
        init: GroupController(database, _group),
        builder: (GroupController groupController) => StreamBuilder(
          stream: groupController.stream,
          builder: (BuildContext context, AsyncSnapshot<GroupModel> groupSnapshot) {

Upvotes: 6

anonymous-dev
anonymous-dev

Reputation: 3489

This is probably how you want to be doing it. Not adding the stream in the contructor because this causes problems when the controller get's rebuild. Because it will add the stream to the contructor once more.

import 'dart:async';
import 'package:get/get.dart';
import 'package:rxdart/rxdart.dart';

class GetStreamController<T> extends GetController {
  final Stream<T> Function() value;
  StreamController<T> _streamController = BehaviorSubject();
  StreamSubscription _streamSubscription;
  Stream<T> get stream => _streamController.stream;

  GetStreamController(this.value);
  @override
  void onInit()
  {
    super.onInit();
    _streamSubscription = value().listen((event) {
      _streamController.add(event);
    });
  }

  @override
  void onClose()
  {
    super.onClose();
    _streamSubscription.cancel();
    _streamController.close();
  }
}

Upvotes: 1

Related Questions