【发布时间】:2018-09-27 11:59:02
【问题描述】:
我知道当我不想再接收任何事件时,我必须取消 Stream 订阅。
即使在收到“完成”事件后,我也必须这样做吗?还是会出现内存泄漏?
传递给另一个 Stream 的 addStream 的 Stream 会发生什么情况?他们会自动取消吗?
StreamSink 方面的相同问题如果流已经完成,我是否必须关闭它们?
【问题讨论】:
我知道当我不想再接收任何事件时,我必须取消 Stream 订阅。
即使在收到“完成”事件后,我也必须这样做吗?还是会出现内存泄漏?
传递给另一个 Stream 的 addStream 的 Stream 会发生什么情况?他们会自动取消吗?
StreamSink 方面的相同问题如果流已经完成,我是否必须关闭它们?
【问题讨论】:
简短回答:不,但你应该。 StreamSubscription 或 StreamSink 的合同中没有任何内容要求关闭资源,但是如果您不关闭它们,某些用例可能会导致内存泄漏,即使在某些情况下这样做也是如此可能会令人困惑。这些类的部分混淆在于它们被重载,并且处理两个相当不同的用例:
让我们一次一个地解决这些问题,首先,StreamSubscription:
StreamSubscription当您将listen 发送到Stream 时,您会收到StreamSubscription。一般来说,当您完成收听Stream 时,无论出于何种原因,您都应该关闭订阅。如果选择不这样做,并非所有流都会泄漏内存,但有些流会泄漏 - 例如,如果您正在从文件中读取输入,则不关闭流意味着文件的句柄可能保持打开状态。
所以,虽然不是严格要求,但我会总是在访问完流时cancel。
StreamSinkStreamSink 最常见的实现是StreamController,它是创建Stream 的编程接口。通常,当您的流完成(即所有数据已发出)时,您应该关闭控制器。
这里有点令人困惑。让我们看看这两种情况:
假设您正在创建一个 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 会很有意义。这会向用户发出信号(done 事件),表明文件已被读取,并且是有意义的(例如,您可以在那时关闭 File 资源)。
假设您正在创建一个 API 来收听 HackerNews 上的新闻文章:
Stream<String> readHackerNews();
在这里,关闭底层接收器/控制器的意义不大。 HackerNews 会停止吗?像这样的事件流(或 UI 程序中的 click 处理程序)传统上不会在没有用户访问的情况下“停止”(即取消 StreamSubscription)。
您可以在完成后关闭控制器,但这不是必需的。
希望这是有道理的,可以帮助你!
【讨论】:
listen 与 cancel 匹配时,比查看代码却看不到任何对象生命周期的迹象更容易理解代码。
我发现如果我有这样的代码:
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;
}
希望这会有所帮助!
【讨论】: