Flutter 中的异步事件处理之Stream、StreamController源码解析(一)

1,470 阅读13分钟

基本概念

Flutter 中的 Stream(流)是一个用于异步事件处理的重要概念,它允许你在应用程序中传递和监听数据的变化。Stream 通常与 StreamController 一起使用,StreamController 用于管理流的数据并将数据推送给监听者。

Sink

/// A generic destination for data.
///
/// Multiple data values can be put into a sink, and when no more data is
/// available, the sink should be closed.
///
/// This is a generic interface that other data receivers can implement.
abstract class Sink<T> {}

根据官方文档解释:

  • 抽象类 Sink<T> 表示一个数据接收器,用于接收泛型类型 T 的数据。
  • 抽象类是不能被直接实例化的,而是需要被其他类继承或实现。

add

abstract class Sink<T> {
  /// Adds [data] to the sink.
  ///
  /// Must not be called after a call to [close].
  void add(T data);
}

这是一个抽象方法,用于将数据添加到接收器中。开发者需要在实现这个接口时提供方法的具体实现。它要求传入一个类型为 T 的数据,将其添加到接收器中。

close

abstract class Sink<T> {
  /// Closes the sink.
  ///
  /// The [add] method must not be called after this method.
  ///
  /// Calling this method more than once is allowed, but does nothing.
  void close();
}

这是另一个抽象方法,用于关闭接收器。关闭接收器表示不再接受新的数据。与 add 方法一样,开发者需要在实现时提供具体的关闭逻辑。同时,根据接收器的实现,可能允许多次调用 close 方法,但多次调用什么也不做。

EventSink

/// A [Sink] that supports adding errors.
///
/// This makes it suitable for capturing the results of asynchronous
/// computations, which can complete with a value or an error.
///
/// The [EventSink] has been designed to handle asynchronous events from
/// [Stream]s. See, for example, [Stream.eventTransformed] which uses
/// `EventSink`s to transform events.
abstract class EventSink<T> implements Sink<T> {}

EventSink 是一个抽象类,它实现了 Sink<T> 接口,表示它是一个数据接收器。它用于处理异步计算的结果,这些计算可能产生值或错误。它通过泛型参数 T 来指定可以接收的数据类型,与前面提到的 Sink<T> 相似。

EventSink<T> 是一个用于处理异步事件的接口,它可以接收数据事件和错误事件,并提供关闭接收器的方法。这种设计非常适用于处理异步计算的结果,例如处理来自 Stream 的异步事件。

add

abstract class EventSink<T> implements Sink<T> {
  /// Adds a data [event] to the sink.
  ///
  /// Must not be called on a closed sink.
  void add(T event);
}

这是一个方法,用于向接收器添加数据事件 event。与普通的 Sink 接口相同,它要求传入类型为 T 的数据事件,并将其添加到接收器中。但是,请注意,这里使用了术语 "event" 而不是 "data",因为这个接口主要用于处理异步事件。

addError

abstract class EventSink<T> implements Sink<T> {
  /// Adds an [error] to the sink.
  ///
  /// Must not be called on a closed sink.
  void addError(Object error, [StackTrace? stackTrace]);
}

这是另一个方法,用于向接收器添加错误信息。它允许你将一个错误对象 error 添加到接收器中,还可以选择性地传递与错误相关的堆栈信息 stackTrace。这对于捕获异步计算的错误非常有用。

close

abstract class EventSink<T> implements Sink<T> {
  /// Closes the sink.
  ///
  /// Calling this method more than once is allowed, but does nothing.
  ///
  /// Neither [add] nor [addError] must be called after this method.
  void close();
}

与普通的 Sink 接口一样,这个方法用于关闭接收器,表示不再接受新的数据。与之前提到的 Sink 不同的是,它还可以处理错误事件。

StreamSink

/// A object that accepts stream events both synchronously and asynchronously.
///
/// A [StreamSink] combines the methods from [StreamConsumer] and [EventSink].
///
/// The [EventSink] methods can't be used while the [addStream] is called.
/// As soon as the [addStream]'s [Future] completes with a value, the
/// [EventSink] methods can be used again.
///
/// If [addStream] is called after any of the [EventSink] methods, it'll
/// be delayed until the underlying system has consumed the data added by the
/// [EventSink] methods.
///
/// When [EventSink] methods are used, the [done] [Future] can be used to
/// catch any errors.
///
/// When [close] is called, it will return the [done] [Future].
abstract class StreamSink<S> implements EventSink<S>, StreamConsumer<S> {}
  • 定义了一个抽象类 StreamSink<S>,它表示一个对象,可以同时接收同步和异步的流事件
  • StreamSink 组合了 StreamConsumerEventSink 的方法。
  • 它提供了关闭接收器和处理完成的功能。这对于处理数据流非常有用。
  • 异步和同步事件的处理:StreamSink 允许你同时处理同步事件和异步事件。EventSink 方法在调用 addStream 方法期间无法使用,但一旦 addStream 方法的 Future 完成并返回,就可以再次使用这些方法。

close

abstract class StreamSink<S> implements EventSink<S>, StreamConsumer<S> {
  /// Tells the stream sink that no further streams will be added.
  ///
  /// This allows the stream sink to complete any remaining work and release
  /// resources that are no longer needed
  ///
  /// Returns a future which is completed when the stream sink has shut down.
  /// If cleaning up can fail, the error may be reported in the returned future,
  /// otherwise it completes with `null`.
  ///
  /// Returns the same future as [done].
  ///
  /// The stream sink may close before the [close] method is called, either due
  /// to an error or because it is itself providing events to someone who has
  /// stopped listening. In that case, the [done] future is completed first,
  /// and the `close` method will return the `done` future when called.
  ///
  /// Unifies [StreamConsumer.close] and [EventSink.close] which both mark their
  /// object as not expecting any further events.
  Future close();
}

这是一个方法,用于告诉流事件接收器,不会再添加更多的流。这允许流事件接收器完成任何剩余的工作并释放不再需要的资源。该方法返回一个 Future,该 Future 在流事件接收器关闭时完成。如果关闭过程中发生错误,错误可能会在返回的 Future 中报告。

done

abstract class StreamSink<S> implements EventSink<S>, StreamConsumer<S> {

  /// Return a future which is completed when the [StreamSink] is finished.
  ///
  /// If the `StreamSink` fails with an error,
  /// perhaps in response to adding events using [add], [addError] or [close],
  /// the [done] future will complete with that error.
  ///
  /// Otherwise, the returned future will complete when either:
  ///
  /// * all events have been processed and the sink has been closed, or
  /// * the sink has otherwise been stopped from handling more events
  ///   (for example by canceling a stream subscription).
  Future get done;
}

这是一个属性,它返回一个 Future,该 Future 在流事件接收器完成时完成。如果流事件接收器失败并导致错误(例如通过 addaddErrorclose 添加事件时出错),则 doneFuture 将以该错误完成。否则,doneFuture 将在以下情况之一完成:

  • 所有事件都已处理并且接收器已关闭。
  • 接收器已停止处理更多事件(例如,取消了流订阅)。

StreamController

abstract class StreamController<T> implements StreamSink<T> {}

定义了一个抽象类,表示一个数据流控制器。它通过泛型参数 T 来指定可以处理的事件的类型。这个控制器允许向它的 stream 发送数据、错误和完成事件。

stream

/// The stream that this controller is controlling.
Stream<T> get stream;

这个属性允许开发者获取到由 StreamController 控制的流对象,然后开发者可以将该流提供给其他部分的代码,以便监听和处理从控制器发出的事件。流通常用于异步操作和事件通知,开发者可以通过监听这个流来获取流中传递的数据、错误和完成事件。

onListen

/// The callback which is called when the stream is listened to.
///
/// May be set to `null`, in which case no callback will happen.
abstract void Function()? onListen;
  • 当流被监听时调用的回调函数。
  • 可以设置为 null,在这种情况下不会触发任何回调。

这个属性允许你设置一个回调函数,当某个代码块监听这个流时,该回调函数将被调用。你可以在回调函数中执行一些特定的操作,以响应流的被监听事件。如果不需要监听回调,你可以将它设置为 null,则不会触发任何回调。这个功能对于跟踪流的监听情况或执行特定的初始化操作非常有用。

onPause

/// The callback which is called when the stream is paused.
///
/// May be set to `null`, in which case no callback will happen.
///
/// Pause related callbacks are not supported on broadcast stream controllers.
abstract void Function()? onPause;

这个属性允许你设置一个回调函数,当某个代码块暂停监听这个流时,该回调函数将被调用。你可以在回调函数中执行一些特定的操作,以响应流的暂停事件。如果不需要暂停回调,你可以将它设置为 null,则不会触发任何回调。

请注意,这个回调在广播流控制器上不受支持。广播流是一种特殊类型的流,可以同时被多个监听者监听,因此它不具有暂停和恢复的概念。因此,如果你使用广播流控制器,将 onPause 设置为 null 或者不使用它是合理的。

onResume

/// The callback which is called when the stream is resumed.
///
/// May be set to `null`, in which case no callback will happen.
///
/// Pause related callbacks are not supported on broadcast stream controllers.
abstract void Function()? onResume;

这个属性允许你设置一个回调函数,当某个代码块恢复监听这个流时,该回调函数将被调用。你可以在回调函数中执行一些特定的操作,以响应流的恢复事件。如果不需要恢复回调,你可以将它设置为 null,则不会触发任何回调。

请注意,这个回调在广播流控制器上不受支持。广播流是一种特殊类型的流,可以同时被多个监听者监听,因此它不具有暂停和恢复的概念。因此,如果你使用广播流控制器,将 onResume 设置为 null 或者不使用它是合理的。

onCancel

/// The callback which is called when the stream is canceled.
///
/// May be set to `null`, in which case no callback will happen.
abstract FutureOr<void> Function()? onCancel;

这个属性允许你设置一个回调函数,当某个代码块取消监听这个流时,该回调函数将被调用。你可以在回调函数中执行一些特定的操作,以响应流的取消事件。如果不需要取消回调,你可以将它设置为 null,则不会触发任何回调。

需要注意的是,onCancel 回调函数返回的是一个 FutureOr<void>,表示它可以是一个异步操作,也可以是一个同步操作。这意味着你可以在回调函数中执行异步任务,并等待它们完成。在流被取消后,该回调函数的执行将帮助你处理相关的清理工作。

sink

/// Returns a view of this object that only exposes the [StreamSink] interface.
StreamSink<T> get sink;

这个属性允许你获取一个对象视图,该视图只暴露了 StreamSink<T> 接口的方法和功能。通过这个视图,你可以将对象的功能限制为仅支持向流中添加数据、错误和完成事件,而不暴露其他与流控制器相关的方法。

isClosed

/// Whether the stream controller is closed for adding more events.
///
/// The controller becomes closed by calling the [close] method.
/// New events cannot be added, by calling [add] or [addError],
/// to a closed controller.
///
/// If the controller is closed,
/// the "done" event might not have been delivered yet,
/// but it has been scheduled, and it is too late to add more events.
bool get isClosed;
  • 流控制器是否已关闭,不再接受添加更多事件。
  • 通过调用 [close] 方法,控制器可以变为已关闭状态。
  • 一旦流控制器已关闭,就无法再通过调用 [add] 或 [addError] 添加新事件。
  • 如果流控制器已关闭,"done" 事件可能尚未被传递,但它已被安排执行,因此无法再添加更多事件。

对于管理流的生命周期和确保不会在控制器已关闭后再次添加事件非常有用。

isPaused

/// Whether the subscription would need to buffer events.
///
/// This is the case if the controller's stream has a listener and it is
/// paused, or if it has not received a listener yet. In that case, the
/// controller is considered paused as well.
///
/// A broadcast stream controller is never considered paused. It always
/// forwards its events to all uncanceled subscriptions, if any,
/// and let the subscriptions handle their own pausing and buffering.
bool get isPaused;
  • 订阅是否需要缓冲事件。
  • 如果控制器的流具有一个监听者并且该监听者处于暂停状态,或者如果它尚未收到监听者,那么控制器也被视为处于暂停状态。
  • 广播流控制器永远不被视为处于暂停状态。它始终将其事件转发给所有未取消的订阅(如果有的话),并让订阅自行处理暂停和缓冲。

需要注意的是,广播流控制器(Broadcast Stream Controller)不会被视为处于暂停状态。它始终将事件转发给所有未取消的订阅,而订阅可以自行处理暂停和缓冲,因此 isPaused 不适用于广播流控制器。这个属性主要用于单播流控制器(Single-subscription Stream Controller)。

hasListener

/// Whether there is a subscriber on the [Stream].
bool get hasListener;

这个属性用于确定流是否有活动的订阅者。如果 hasListener 返回 true,则表示至少有一个代码块正在监听流,如果返回 false,则表示当前没有任何代码块监听流。这个属性对于确定流的活动状态和是否有监听者非常有用,可以用于在必要时执行特定操作或采取适当的措施。

add、addError、close、done、addStream

/// Sends a data [event].
///
/// Listeners receive this event in a later microtask.
///
/// Note that a synchronous controller (created by passing true to the `sync`
/// parameter of the `StreamController` constructor) delivers events
/// immediately. Since this behavior violates the contract mentioned here,
/// synchronous controllers should only be used as described in the
/// documentation to ensure that the delivered events always *appear* as if
/// they were delivered in a separate microtask.
void add(T event);

/// Sends or enqueues an error event.
///
/// Listeners receive this event at a later microtask. This behavior can be
/// overridden by using `sync` controllers. Note, however, that sync
/// controllers have to satisfy the preconditions mentioned in the
/// documentation of the constructors.
void addError(Object error, [StackTrace? stackTrace]);

/// Closes the stream.
///
/// No further events can be added to a closed stream.
///
/// The returned future is the same future provided by [done].
/// It is completed when the stream listeners is done sending events,
/// This happens either when the done event has been sent,
/// or when the subscriber on a single-subscription stream is canceled.
///
/// A broadcast stream controller will send the done event
/// even if listeners are paused, so some broadcast events may not have been
/// received yet when the returned future completes.
///
/// If no one listens to a non-broadcast stream,
/// or the listener pauses and never resumes,
/// the done event will not be sent and this future will never complete.
Future close();

/// A future which is completed when the stream controller is done
/// sending events.
///
/// This happens either when the done event has been sent, or if the
/// subscriber on a single-subscription stream is canceled.
///
/// A broadcast stream controller will send the done event
/// even if listeners are paused, so some broadcast events may not have been
/// received yet when the returned future completes.
///
/// If there is no listener on a non-broadcast stream,
/// or the listener pauses and never resumes,
/// the done event will not be sent and this future will never complete.
Future get done;

/// Receives events from [source] and puts them into this controller's stream.
///
/// Returns a future which completes when the source stream is done.
///
/// Events must not be added directly to this controller using [add],
/// [addError], [close] or [addStream], until the returned future
/// is complete.
///
/// Data and error events are forwarded to this controller's stream. A done
/// event on the source will end the `addStream` operation and complete the
/// returned future.
///
/// If [cancelOnError] is `true`, only the first error on [source] is
/// forwarded to the controller's stream, and the `addStream` ends
/// after this. If [cancelOnError] is false, all errors are forwarded
/// and only a done event will end the `addStream`.
/// If [cancelOnError] is omitted or `null`, it defaults to `false`.
Future addStream(Stream<T> source, {bool? cancelOnError});

总结

他们从SinkStreamSink都只是到导入接口,并无直接继承关系,在抽象类方面按照功能解耦,最终由StreamController整合,负责添加的是StreamControlelr,负责监听的是Stream,最终在当前的Zone中执行回调Zone.runUnaryGuarded()Zone类似一个沙盒环境,在APP启动的时候创建。

截屏2023-09-03 16.37.49.png

参考资料

全面深入理解Stream

深入理解 Flutter 中的 Stream (一)

深入理解 Flutter 中的 Stream (二)

异步编程:使用 stream

在 Dart 里使用 Stream

Stream<​T> class