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

时间:2018-04-17 13:28:19

标签: stream dart

我知道当我不想再接收任何活动时,我必须取消Stream订阅。 即使在我收到“完成”后,我是否也必须这样做?事件?或者我是否会泄漏内存?

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

如果流已经完成,我必须在StreamSink方面关闭它们吗?

2 个答案:

答案 0 :(得分:5)

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

  1. 资源流(如文件I / O,网络访问)
  2. 事件流(如点击处理程序)
  3. 让我们一次解决这些问题,首先,StreamSubscription

    StreamSubscription

    当您listenStream时,您会收到StreamSubscription。通常,当您完成收听Stream时,出于任何原因,您应该关闭订阅。如果不选择,并非所有流都会泄漏内存,但有些会 - 例如,如果您正在从文件读取输入,而不是关闭流意味着文件的句柄可能保持打开状态。

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

    StreamSink

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

    这里有点令人困惑。让我们来看看这两种情况:

    文件I / O

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

    Stream<String> readLines(String path);
    

    要实现此目的,您可以使用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;
    }
    

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

    活动

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

    Stream<String> readHackerNews();
    

    这对关闭底层接收器/控制器没有多大意义。 HackerNews是否停止?像这样的事件流(或UI程序中的click处理程序)传统上不会停止&#34;没有用户访问它(即取消StreamSubscription)。

    完成后你可以关闭控制器,但不是必需的。

    希望有意义并帮助你!

答案 1 :(得分:2)

在我的案例中,我发现如果我有这样的代码:

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

  ......

  return controller.stream;
}

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

controller.close()

有关OnCancel事件的事件处理程序,请参见下文:

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

  //TODO: your code here

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

  return controller.stream;
}

希望这会有所帮助!