【问题标题】:How do I close a stream when my Get Controller is deleted from memory?当我的 Get Controller 从内存中删除时,如何关闭流?
【发布时间】:2020-05-13 04:40:26
【问题描述】:

我正在使用以下软件包 https://pub.dev/packages/get

我有以下控制器

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();
  }
}

但是当我调用它时,永远不会调用 dispose。我这样称呼它

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

我希望每当控制器从内存中删除时调用我的控制器的 dispose 方法。

我注意到 GetBuilder 有一个 dispose 回调。它需要来自小部件的状态。那么我是否需要使包含控制器的小部件成为有状态的?或者我是否需要传递一个新的状态小部件来保存状态?文档并不是全部都清楚。如何在我的控制器上调用 dispose?

我注意到每当控制器从内存中删除时都会有一个控制台日志,难道没有回调以便我可以在那里关闭流吗?我真的很想避免使小部件有状态。

编辑

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();
  }
}

生成以下日志

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

尝试关闭控制器时出现错误

【问题讨论】:

  • 您希望何时调用dispose 方法?
  • 当小部件从内存中删除但我希望它在小部件从树中删除时发生。但总的来说,我只想知道如何利用我的 GetBuilder 的 dispose 属性。
  • 没有监听器可以放在 Dart 中的类上,当对象从内存中删除时会被调用。小部件中的 dispose 方法 用于将它们从小部件树中删除。
  • 那么如何使用 Get 关闭流?如何使用 GetBuilder 的 dispose 属性?如果我通过 statefull 小部件的 dispose 方法,我如何引用 Controller?
  • 简单的答案?你不能。 get 包中的小部件不会为清理代码公开dispose 属性,因此您无法真正轻松地做您想做的事情。不过,出于好奇,您为什么要使用 get 而不是 provider 之类的东西?

标签: flutter dart


【解决方案1】:

如果您在 GetController 中插入“dispose”,它将被忽略。这是因为 disposing 是 StatefulWidget 类中用于丢弃小部件的方法,而不是用于丢弃控制器,尤其是因为 Get 会在不再需要时自动智能地丢弃控制器以释放资源。如果要关闭流,Get 会自动执行,只要将流插入 onClose 方法即可。

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();
  }
}

如果您使用的是旧版本的 Get,您可以手动使用相同的关闭和关闭方法:

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

【讨论】:

  • 太好了,我显然需要更新我的 Get。我尝试在 close 方法中关闭流并收到以下错误 I/flutter (23404): log if close is invoked I/flutter (23404): Close can't be called I/flutter (23404): [GET] GroupController deleted from memory 所以它确实调用了该方法但随后记录了无法调用关闭?
  • 我在答案底部添加了用于控制器的代码。我做错了什么?
  • 啊,好吧,所以需要先排空流。所以我必须实现一个future,它会耗尽流然后关闭控制器。不确定这有多安全。
  • 我在下面添加了工作代码,但接受了你的回答,因为我想找到关闭回调
【解决方案2】:

这可能就是您想要的方式。不要在构造函数中添加流,因为这会在控制器重建时导致问题。因为它将再次将流添加到构造函数。

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();
  }
}

【讨论】:

  • 这是因为你没有使用本地流,你已经在本地流中添加了一个现有的流,所以你需要先排空你的流。日志显示一个通用错误,因为 Get 有一个 try catch,并且在 close 方法中抛出任何错误,它都会抛出同样的异常,但实际上 close 正在被调用,但是流有一个错误,因为它没有被耗尽并且这个错误触发了 Get 的 catch (e)。如果没有_streamController.addStream(database.groupStream(group));这个额外的程序是不必要的。您的代码是 100% 安全的
  • 好的,现在我遇到了以下问题。我的第二个 GetBuilder 调用 close 方法,只要它从试图关闭流的小部件树中删除。我实际上是在 github 页面上发布的,因为我不确定应该如何将 Streams 与控制器一起使用 github.com/jonataslaw/get/issues/94
  • 我相信这个问题在上次更新中得到了解决,这是一个拼写错误,导致任何 GetBuilder 都可以调用主要的 GetBuilder 设备。感谢您报告此错误,它正在清除测试,并添加了具有关闭子页面流的测试。
  • 我也更新了代码,因为在构造函数中分配流时遇到了问题。因为每次重建都会调用构造函数。但是 initState 没有!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-18
  • 2022-12-17
相关资源
最近更新 更多