Dart:我必须取消Stream订阅并关闭StreamSinks吗?

Tho*_*mas 16 stream dart

我知道Stream当我不想再收到任何活动时我必须取消订阅.即使我收到"完成"活动后,我还有这个吗?或者我是否有内存泄漏?

传递到addStream另一个Stream的Streams会发生什么?它们会自动取消吗?

对同样的问题StreamSink方面我必须关闭它们,如果流已经做了什么?

mat*_*rey 15

简答:没有.合同中没有任何内容StreamSubscriptionStreamSink 要求关闭资源,在某些情况下,这样做可能会令人困惑.围绕这些类的部分混淆是它们被重载,并处理两个相当不同的用例:

  1. 资源流(如文件I/O,网络访问)
  2. 事件流(如点击处理程序)

让我们一次一个地解决这些问题,首先,StreamSubscription:

StreamSubscription

当你listen到了Stream,你收到了StreamSubscription.在一般情况下,当你倾听到Stream,以任何理由,你应该关闭订阅.如果不选择,并非所有流都会泄漏内存,但有些会 - 例如,如果您正在从文件读取输入,而不关闭流意味着文件的句柄可能保持打开状态.

因此,虽然不是严格要求,但我总是 cancel在完成访问流时.

StreamSink

最常见的实现StreamSinkStreamController,它是一个用于创建的编程接口Stream.通常,当您的流完成(即发出所有数据)时,您应该关闭控制器.

这是让它有点混乱的地方.让我们看看这两种情况:

文件I/O.

想象一下,您正在创建一个API,以逐行异步读取文件:

Stream<String> readLines(String path);
Run Code Online (Sandbox Code Playgroud)

要实现这一点,您可以使用StreamController:

Stream<String> readLines(String path) {
  SomeFileResource someResource;
  StreamController<String> controller;
  controller = new StreamController<String>(
    onListen: () {
      someResource = new SomeFileResource(path);
      // TODO: Implement adding to the controller.
    },
  );
  return controller.stream;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,它将使很多意义关闭controller,当最后一行已经被读出.这向用户发出信号(已完成事件),该文件已被读取并且有意义(例如,您可以在此时关闭文件资源).

活动

想象一下,您正在创建一个API来收听HackerNews上的新闻文章:

Stream<String> readHackerNews();
Run Code Online (Sandbox Code Playgroud)

这里关闭底层接收器/控制器没有多大意义.HackerNews会不会停止?像这样的事件流(或clickUI程序中的处理程序)传统上不会在没有用户访问它的情况下"停止"(即取消StreamSubscription).

可以在完成后关闭控制器,但这不是必需的.


希望有意义并帮助你!

  • 我认为答案确实是“是的,应该”,而“否,您没有*必须”只是从技术上讲是正确的(其余文字详细说明)。就是说,在某些情况下您不需要这样做,但是总会在您自己之后进行清理会更容易(将少数情况例外,那就是一些不那么容易*并且*知道您不需要的情况)。当您看到订阅上的“侦听”与“取消”相匹配时,比看代码而不看对象生命周期的任何迹象要容易理解代码。 (2认同)

Ser*_*gey 10

我发现在我的情况下,如果我有这样的代码:

Stream<String> readHackerNews(String path) {  
  StreamController<String> controller = StreamController<String>();

  ......

  return controller.stream;
}
Run Code Online (Sandbox Code Playgroud)

我看到一条警告消息“关闭‘dart.core.Sink’的实例。” 在 Visual Studio 代码中。为了解决这个警告,我添加了

controller.close()
Run Code Online (Sandbox Code Playgroud)

到 OnCancel 事件的事件处理程序,见下文:

Stream<String> readHackerNews(String path) {  
  StreamController<String> controller = StreamController<String>();

  //TODO: your code here

  controller.onCancel = () {
    controller.close();
  };

  return controller.stream;
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!