Flutter 从源码认识Stream机制

Stream的基本使用

scss 复制代码
//1、创建一个流控制对象,只要用来控制流的暂停、取消和订阅
StreamController _controller = StreamController();

//2、实现对一个流的订阅和监听事件
_controller.stream.listen((event) {
print("event==$event");
});

//3、添加一个事件
_controller.add("123");

StreamController类

职责是一个抽象类,用于创建一个可以发送数据和接收数据的可监听对象。 _StreamController 是StreamController的真正实现类 工厂构造方法

csharp 复制代码
factory StreamController(
      {void onListen()?,
      void onPause()?,
      void onResume()?,
      FutureOr<void> onCancel()?,
      bool sync = false}) {
    return sync
        ? _SyncStreamController<T>(onListen, onPause, onResume, onCancel)
        : _AsyncStreamController<T>(onListen, onPause, onResume, onCancel);

我们使用StreamController的时候会这样 StreamController controller = StreamController(); 但是StreamController是个抽象,不能被实例化,主要他使用了工厂构造,最后使用他的子类去实例化。

_SyncStreamController和_AsyncStreamController就是StreamController的子类

csharp 复制代码
//异步控制器
class _AsyncStreamController<T> = _StreamController<T>
    with _AsyncStreamControllerDispatch<T>;

//同步控制器
class _SyncStreamController<T> = _StreamController<T>
    with _SyncStreamControllerDispatch<T>;

可以看到_AsyncStreamController和_SyncStreamController直接继承了_StreamController。

而_StreamController是StreamController的真正的实现类

csharp 复制代码
//继承关系链
abstract class _StreamController<T> implements _StreamControllerBase<T> 
 
abstract class _StreamControllerBase<T>
    implements
        StreamController<T>,
        _StreamControllerLifecycle<T>,
        _EventSink<T>,
        _EventDispatch<T> {

_controller.stream就是Stream对象

Stream 提供了一种接收事件序列的方法。每个事件要么是数据事件(也称为流的元素),要么是错误事件(这是某件事情失败的通知)。

这个流机制也算是一个生产者和消费者模式。 生产者就是_controller.add("123"); 消费者就是listen监听了 那我们来看看stream内部是如何实现这个机制的?

listen监听

我们得先注册一下监听事件,添加对此流的订阅,才能接收到生产者的通知。

csharp 复制代码
  StreamSubscription<T> listen(void onData(T event)?,
      {Function? onError, void onDone()?, bool? cancelOnError});
 
 
   StreamSubscription<T> listen(void onData(T data)?,
      {Function? onError, void onDone()?, bool? cancelOnError}) {
    cancelOnError ??= false;
    StreamSubscription<T> subscription =
        _createSubscription(onData, onError, onDone, cancelOnError);
    _onListen(subscription);
    return subscription;
  }
 

这个listen方法是Stream类的方法,返回的是一个订阅对象StreamSubscription。并且是空的实现,需要子类去实现它。


    
 
我们看看是哪个类实现了Stream类。它有很多的实现类,我选一个主要的类_StreamImpl。

_StreamImpl 是 Stream的继承类,它也是个抽象类,我去找它的最终实现类_ControllerStream

abstract class _StreamImpl<T> extends Stream<T>

class _ControllerStream<T> extends _StreamImpl<T>

我们可以发现在_StreamController 有个方法,用来获取流对象的,正好是Stream的子类_ControllerStream

Stream<T> get stream => _ControllerStream<T>(this);

我们来看看_ControllerStream类
 
 StreamSubscription<T> _createSubscription(void onData(T data)?,
          Function? onError, void onDone()?, bool cancelOnError) =>
      _controller._subscribe(onData, onError, onDone, cancelOnError);

_controller就是抽象类_StreamControllerLifecycle的实例对象, _subscribe是个抽象方法,需要子类去实现它。

csharp 复制代码
abstract class _StreamController<T> implements _StreamControllerBase<T>
abstract class _StreamControllerBase<T>
 implements
     StreamController<T>,
     _StreamControllerLifecycle<T>,
     EventSink<T>,
     _EventDispatch<T>
 

从上面的代码可以看出,最终是_StreamController实现了_subscribe方法 我们把_subscribe方法代码拿出来

ini 复制代码
StreamSubscription<T> _subscribe(void onData(T data)?, Function? onError,
      void onDone()?, bool cancelOnError) {
    if (!_isInitialState) {
      throw StateError("Stream has already been listened to.");
    }
    //创建一个订阅对象
    _ControllerSubscription<T> subscription = _ControllerSubscription<T>(
        this, onData, onError, onDone, cancelOnError);

    _PendingEvents<T>? pendingEvents = _pendingEvents;
    _state |= _STATE_SUBSCRIBED;
    if (_isAddingStream) {
      _StreamControllerAddStreamState<T> addState = _varData as dynamic;
      addState.varData = subscription;
      addState.resume();
    } else {
      _varData = subscription;
    }
    subscription._setPendingEvents(pendingEvents);
    subscription._guardCallback(() {
      _runGuarded(onListen);
    });

    return subscription;
  }

这个方法是关键,从方法名字我们就可以知道这是一个订阅方法,实现对一个事件的订阅。 我们看一下_ControllerSubscription,它的父类是StreamSubscription。

StreamSubscription 类

StreamSubscription 是一个抽象接口类 文档上描述 订阅向listen提供事件,并保存用于处理事件的回调。订阅还可用于取消订阅事件,或暂时暂停流中的事件。

下面是它的一些抽象方法

csharp 复制代码
    ///取消订阅事件
  Future<void> cancel();

 ///处理订阅事件
  void onData(void handleData(T data)?);

 ///完成订阅事件
  void onDone(void handleDone()?);

  ///暂停订阅事件
  void pause([Future<void>? resumeSignal]);

   ///恢复订阅事件
  void resume();
scala 复制代码
class _BufferingStreamSubscription<T>
    implements StreamSubscription<T>, _EventSink<T>, _EventDispatch<T>
    
class _ControllerSubscription<T> extends _BufferingStreamSubscription<T> 

发起数据通知

接着我们再看看数据添加方法,这个方法就是用来发起数据通知的

void 复制代码
   if (hasListener) {
     _sendData(value);
   } else if (_isInitialState) {
     _ensurePendingEvents().add(_DelayedData<T>(value));
   }
 }

// 这个_sendData方法是抽象类_EventDispatch的方法
 abstract class _EventDispatch<T> {
   void _sendData(T data);
   void _sendError(Object error, StackTrace stackTrace);
   void _sendDone();
 }
   

经过查找发现 _AsyncStreamControllerDispatch类实现了_sendData的方法

继承关系链

mixin 复制代码
abstract class _StreamController<T> implements _StreamControllerBase<T>
abstract class _StreamControllerBase<T> implements StreamController<T>, _StreamControllerLifecycle<T>,_EventSink<T>,_EventDispatch<T> {}

_AsyncStreamControllerDispatch类实现的方法如下
  void _sendData(T data) {
    _subscription._addPending(_DelayedData<T>(data));
  }


_subscription 就是_ControllerSubscription的实例对象
如下代码所示

  _ControllerSubscription<T> get _subscription {
    assert(hasListener);
    Object? varData = _varData;
    if (_isAddingStream) {
      _StreamControllerAddStreamState<Object?> streamState = varData as dynamic;
      varData = streamState.varData;
    }
    return varData as dynamic;
  }

  varData 这个很熟悉就是上面的_subscribe方法里面实例化ControllerSubscription对象赋值给varData,这个varData
  实际就是ControllerSubscription对象。

继承关系链

scala 复制代码
class _ControllerSubscription<T> extends _BufferingStreamSubscription<T>
class _BufferingStreamSubscription<T> implements StreamSubscription<T>, _EventSink<T>, _EventDispatch<T>

接着我们再来看看 _subscription._addPending(_DelayedData(data));

代码如下,这个方法是_BufferingStreamSubscription类实现的

scss 复制代码
   void _addPending(_DelayedEvent event) {
    var pending = _pending ??= _PendingEvents<T>();
    pending.add(event);
    if (!_hasPending) {
      _state |= _STATE_HAS_PENDING;
      if (!_isPaused) {
        pending.schedule(this);
      }
    }
  }

这个方法主要是添加一个处理事件,接着我们看看schedule方法

ini 复制代码
   void schedule(_EventDispatch<T> dispatch) {
     if (isScheduled) return;
     assert(!isEmpty);
     if (_eventScheduled) {
       assert(_state == stateCanceled);
       _state = stateScheduled;
       return;
     }
     scheduleMicrotask(() {
       int oldState = _state;
       _state = stateUnscheduled;
       if (oldState == stateCanceled) return;
       handleNext(dispatch);
     });
     _state = stateScheduled;
   }
 放到微任务中执行handleNext

   void handleNext(_EventDispatch<T> dispatch) {
     assert(!isScheduled);
     assert(!isEmpty);
     _DelayedEvent event = firstPendingEvent!;
     _DelayedEvent? nextEvent = event.next;
     firstPendingEvent = nextEvent;
     if (nextEvent == null) {
       lastPendingEvent = null;
     }
     event.perform(dispatch);
   }

_DelayedEvent是个抽象类,perform方法是需要子类去实现 它的子类就是_DelayedData

scala 复制代码
class _DelayedData<T> extends _DelayedEvent<T> {
 final T value;
 _DelayedData(this.value);
 void perform(_EventDispatch<T> dispatch) {
   dispatch._sendData(value);
 }
}

我们看_sendData这个方法,这个方法也是在_BufferingStreamSubscription类中实现的。 整个代码看下来我们只需要关心 _zone.runUnaryGuarded(_onData, data); 这个是实现数据发送的关键。 也是订阅者和被订阅者之间的中间角色,起着承上启下的作用。

scss 复制代码
 void _sendData(T data) {
    assert(!_isCanceled);
    assert(!_isPaused);
    assert(!_inCallback);
    bool wasInputPaused = _isInputPaused;
    _state |= _STATE_IN_CALLBACK;
    _zone.runUnaryGuarded(_onData, data);
    _state &= ~_STATE_IN_CALLBACK;
    _checkState(wasInputPaused);
  }

Zone 被称做是沙箱,在 Dart 中,Zone 是用于隔离代码执行环境的概念。Zone 可以看作是一种执行上下文,它可以用于控制代码执行过程中的一些行为,比如异常处理、日志记录、资源管理等。Zone 中的 run 方法允许你在指定的 Zone 中运行一段代码块。 这里不继续深究下去,有兴趣的可以看看。我们只需要知道调用runUnaryGuarded这个方法。它就会回调_onData函数,并将参数data传给_onData方法。 _onData这个函数就是我们listen监听里的匿名函数,最终会回调那里去。

最后结语

虽然看不懂源码是一件枯燥无聊的事,但是多看几遍或许会变成一件有趣的事。如果要想深入学习flutter,阅读源码是必须要跨过的坎。 当然我写的也不是很好,只是纯粹记录学习从步骤一步步看源码的过程。有不满的,可以提提意见,但不要乱喷。

相关推荐
AiFlutter3 小时前
Flutter之Package教程
flutter
Mingyueyixi7 小时前
Flutter Spacer引发的The ParentDataWidget Expanded(flex: 1) 惨案
前端·flutter
crasowas16 小时前
Flutter问题记录 - 适配Xcode 16和iOS 18
flutter·ios·xcode
老田低代码2 天前
Dart自从引入null check后写Flutter App总有一种难受的感觉
前端·flutter
AiFlutter2 天前
Flutter Web首次加载时添加动画
前端·flutter
ZemanZhang3 天前
Flutter启动无法运行热重载
flutter
AiFlutter4 天前
Flutter-底部选择弹窗(showModalBottomSheet)
flutter
帅次4 天前
Android Studio:驱动高效开发的全方位智能平台
android·ide·flutter·kotlin·gradle·android studio·android jetpack
程序者王大川4 天前
【前端】Flutter vs uni-app:性能对比分析
前端·flutter·uni-app·安卓·全栈·性能分析·原生
yang2952423614 天前
使用 Vue.js 将数据对象的值放入另一个数据对象中
前端·vue.js·flutter