Stream 是Flutter 中非常常用的一個概念,但是他并不是Flutter 所獨有的,而是在Dart中默認封裝的,他和Future 一樣,都可以異步執行,但是相對于Future Stream 更加高級.
Stream代表著事件流,通過Stream可以快速的實現事件流驅動業務邏輯,界面通過訂閱事件,針對事件轉換最后通過響應事件完成頁面布局,而在整個Stream流過程中,有四個角色分別扮演了不同的角色
1.StreamController
字面意思,管理調度整個事件流的流程,并保存整個事件流中所需要的對象,便于管理和使用
2.StreamSink
事件的開始入口,所有的同步和異步事件都是從這里開始的 ,提供了add 和 addStream 等方法
3.Stream
事件本身,可以被轉換和監聽,訂閱后返回StreamSubscription 對象
4.StreamSubscription
訂閱Stream 后得到的對象,可以管理訂閱過的各種操作,例: cancel() pause();
整個事件流的流經過程就是,先創建Stream ,創建回調方法并訂閱, 再通過StreamSink 添加事件源,在訂閱的過程中可以使用StreamSubscription管理這個訂閱狀態,最后回調 Stream 訂閱的回調方法,仔細想一下整個過程其實和 StreamController 并沒有太大的關系, 但是整個過程如果離開了StreamController , 沒有從中間調度的過程,整個代碼的邏輯和代碼量都是非常讓人頭疼的,
在這里再吐槽一下dart 源碼的結構,雖然通過 with 拼接是一個很好的方式,但是這樣對剛剛學習的來說是非常不友好的,我整個學習過程中在學習控件的時候并沒有太多的感觸,但是在接觸Element 和RenderObject 后,心里已經產生了這個想法,今天上午在看Stream的過程更是讓我再次認同了這個想法,不過話雖然這么說,還是需要看的,自己也算是看了一些源碼了,總結了一下dart源碼怎么看,正好利用我對Stream的學習,分享一下我是怎么看源碼的. 廢話不多說,上套路!!!
這里先貼一下我的環境,
D:\User\flutter_app1>flutter --version
Flutter 1.20.3 ? channel stable ? https://github.com/flutter/flutter.git
Framework ? revision 216dee60c0 (6 weeks ago) ? 2020-09-01 12:24:47 -0700
Engine ? revision d1bc06f032
Tools ? Dart 2.9.2
1.理清構架
想要學習源碼,首先你要知道各個類在這個功能中所扮演的角色,不必清楚每個方法是如何實現的,但是你需要他在整個流程中存在的目的, 這些很簡單,通過度娘就能獲取到你想要知道的淺顯的介紹,這里回想一下Stream 的幾個角色,想想他們的用途,但是他們是如何關聯起來的呢,帶著這個疑問,我們就來從代碼說起.
2.重點突破
StreamController 作為管理和調度中心,他的源碼其實應該就是整個Stream實現的核心,但是你去看一下其實他的方法非常的亂,沒有一個主線將它連接起來, 這里我們看一下上面我們對整個Stream 的流程總結,我們就按照總結的流程來看一下Stream 的工作過程, 先看Stream
1>Stream 的創建和訂閱
我們首次獲取 Stream 是通過StreamController 來獲取的,
// Return a new stream every time. The streams are equal, but not identical.
///在獲取Stream 的時候,每次都獲取一個新的Stream , 流是相等的,但是并不完全相同,
Stream<T> get stream => _ControllerStream<T>(this);
根據創建的實體我們看一下他的訂閱 也就是listen 方法,
abstract class _StreamImpl<T> extends Stream<T> {
////可以傳入onError 和 onDone 也就是錯誤和完成回調
StreamSubscription<T> listen(void onData(T data)?, {Function? onError, void onDone()?, bool? cancelOnError}) {
cancelOnError ??= false;
////創建訂閱 _createSubscription 這個方法被子類重寫了
StreamSubscription<T> subscription =_createSubscription(onData, onError, onDone, cancelOnError);
_onListen(subscription);
return subscription;
}
}
在這里發現這個方法并不是_ControllerStream實現的,而是由他的父類_StreamImpl實現的,代碼我已經放在上面了,
class _ControllerStream<T> extends _StreamImpl<T> {
_StreamControllerLifecycle<T> _controller;
_ControllerStream(this._controller);
StreamSubscription<T> _createSubscription(void onData(T data)?,
Function? onError, void onDone()?, bool cancelOnError) =>
_controller._subscribe(onData, onError, onDone, cancelOnError);
}
這里我們發現_createSubscription 這個方法又調用了 StreamController 的_subscribe 方法
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;
}
...
return subscription;
}
_varData 就是訂閱后的 subscription 在這里共享了他,以便于在后續接收到數據時找到回調 ,他只能被訂閱一次,
我們發現在創建訂閱過程中使用的是 _ControllerSubscription ,他繼承了 _BufferingStreamSubscription 這個類來創建的訂閱,
_BufferingStreamSubscription(void onData(T data)?, Function? onError,
void onDone()?, bool cancelOnError)
: this.zoned(Zone.current, onData, onError, onDone, cancelOnError);
_BufferingStreamSubscription.zoned(this._zone, void onData(T data)?,
Function? onError, void onDone()?, bool cancelOnError)
: _state = (cancelOnError ? _STATE_CANCEL_ON_ERROR : 0),
_onData = _registerDataHandler<T>(_zone, onData),
_onError = _registerErrorHandler(_zone, onError),
_onDone = _registerDoneHandler(_zone, onDone);
來到創建 StreamSubscription 的這個方法 ,收到了這個onData () 這個方法,并保存了起來,這里我們發現
StreamSubscription 的最終實現子類是 _BufferingStreamSubscription ,記錄一下,這個很重要
controller.stream.listen() --> _ControllerStream.listen() --> _ControllerStream._createSubscription() --> controller._subscribe() --> 返回_ControllerSubscription(); 并執行 zone.runUnaryGuarded()
創建Stream 并訂閱的整個流程大致就是這些方法,
這里我們就把創建 Stream 和 訂閱的這個過程看完了,接下來我們再看 StreamSink 發送事件源的過程
2> StreamSink 發送事件源
說道這里我們就要說一下StreamController 他的創建方法, 這里有一個bool sync ,他控制著是同步執行還是異步執行,
如果 sync 為true 則同步執行,否則異步執行,他默認的是異步執行,也就是說 默認創建StreamController 發送這接收信息之間是異步的,這里先說一下同步和異步的區別,
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);
}
abstract class _SyncStreamControllerDispatch<T>
implements _StreamController<T>, SynchronousStreamController<T> {
void _sendData(T data) {
_subscription._add(data);
}
}
abstract class _AsyncStreamControllerDispatch<T>
implements _StreamController<T> {
void _sendData(T data) {
_subscription._addPending(_DelayedData<T>(data));
}
}
開始說事件源分發
與 Stream 同樣的道理,先在 StreamController 中找到sink ,
/**
* Returns a view of this object that only exposes the [StreamSink] interface.
*/
StreamSink<T> get sink => _StreamSinkWrapper<T>(this);
這里的sink 使用的是_StreamSinkWrapper 來實現,我們來看一下他的送法事件源 即 add 方法
class _StreamSinkWrapper<T> implements StreamSink<T> {
final StreamController _target;
_StreamSinkWrapper(this._target);
void add(T data) {
_target.add(data);
}
}
來到這里我們發現整個 _StreamSinkWrapper 就是一個中轉類,在調用他的add 方法的時候,其實調用的是target.add()方法,即 StreamController 的add 方法
void _add(T value) {
///在 listen 方法中已經調用controller 的 sub
if (hasListener) {
_sendData(value);
} else if (_isInitialState) {
_ensurePendingEvents().add(_DelayedData<T>(value));
}
}
在StreamController 的add方法中我們看到,如果已經_subscribe 方法將state 修改為 _STATE_SUBSCRIBED;即已訂閱的狀態,這里走事件的分發 _sendData(value); 這個方法
這里我們先說一下同步執行的方法
abstract class _SyncStreamControllerDispatch<T>
implements _StreamController<T>, SynchronousStreamController<T> {
void _sendData(T data) {
_subscription._add(data);
}
void _sendError(Object error, StackTrace stackTrace) {
_subscription._addError(error, stackTrace);
}
void _sendDone() {
_subscription._close();
}
}
在同步方法里面,使用的_subscription 即上面所說的_varData 得_add 方法 也就是_BufferingStreamSubscription 的add 方法
///添加數據
void _add(T data) {
assert(!_isClosed);
if (_isCanceled) return;
if (_canFire) {
_sendData(data);
} else {
_addPending(new _DelayedData<T>(data));
}
}
///使用zone 來 調用回調
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);
}
關于異步方法
abstract class _AsyncStreamControllerDispatch<T>
implements _StreamController<T> {
void _sendData(T data) {
_subscription._addPending(_DelayedData<T>(data));
}
void _sendError(Object error, StackTrace stackTrace) {
_subscription._addPending(_DelayedError(error, stackTrace));
}
void _sendDone() {
_subscription._addPending(const _DelayedDone());
}
}
這里使用的是 _subscription._addPending 的這個方法
void _addPending(_DelayedEvent event) {
_StreamImplEvents<T>? pending = _pending as dynamic;
pending ??= _StreamImplEvents<T>();
_pending = pending;
pending.add(event);
if (!_hasPending) {/// 沒有開始循環
_state |= _STATE_HAS_PENDING;
if (!_isPaused) {///沒有被暫停
pending.schedule(this);
}
}
}
這里初始化了 _pending 并將event 添加到里這個_pending 里面,這里如果循環處理事件沒有被開啟,則開啟循環事件處理消息,即 pending.schedule(this);
void schedule(_EventDispatch<T> dispatch) {
if (isScheduled) return;///已經開啟了,則返回
assert(!isEmpty);
if (_eventScheduled) {///事件已經被消費
assert(_state == _STATE_CANCELED);
_state = _STATE_SCHEDULED;
return;
}
////這里開始異步,遍歷 dispatch , 并開啟了循環
scheduleMicrotask(() {
int oldState = _state;
_state = _STATE_UNSCHEDULED;
if (oldState == _STATE_CANCELED) return;
handleNext(dispatch);
});
_state = _STATE_SCHEDULED;
}
////此時是異步執行,使用的是鏈表方式保存的數據 ,會存在異步耗時任務,第一個沒有執行完第二個又進來了,則這個任務會被默認調價到隊尾,
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);
}
///此時是異步執行,使用_BufferingStreamSubscription 的_sendData 方法 執行回調 ,回到同步方法onData
void perform(_EventDispatch<T> dispatch) {
dispatch._sendData(value);
}
如何調用異步的簡單的說一下,由于本人了解的也不是很多,簡單的說一下loop的這個概念
///在我的理解所有的 _AsyncRun 共享同一個loop ,在你添加任務進來的同時,如果其他的 StreamSink 添加進來的任務沒有被消費完,則將你的添加到隊尾, 否則開始新的 異步循環
void _scheduleAsyncCallback(_AsyncCallback callback) {
_AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback);
_AsyncCallbackEntry? lastCallback = _lastCallback;
if (lastCallback == null) {
_nextCallback = _lastCallback = newEntry;
if (!_isInCallbackLoop) {
_AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
} else {
lastCallback.next = newEntry;
_lastCallback = newEntry;
}
}
///開始執行循環,如果你的循環執行完后,再次檢查,如果隊伍還有,則重新開始異步循環
void _startMicrotaskLoop() {
_isInCallbackLoop = true;
try {
// Moved to separate function because try-finally prevents
// good optimization.
_microtaskLoop();
} finally {
_lastPriorityCallback = null;
_isInCallbackLoop = false;
if (_nextCallback != null) {
_AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
}
}
////隊列模式,一個一個取出,并調用callback 回調
void _microtaskLoop() {
for (var entry = _nextCallback; entry != null; entry = _nextCallback) {
_lastPriorityCallback = null;
var next = entry.next;
_nextCallback = next;
if (next == null) _lastCallback = null;
(entry.callback)();
}
}
這個發送事件源的過程也結束了,總結一下
StreamSink.add() --> StreamController.sendData ()
--> 同步: 直接StreamSubscription.sendData()
-->異步: 添加到_pending 隊列中StreamSubscription.addPending , -->如果loop 循環沒有執行 ,則開始循環 即 scheduleMicrotask 異步處理數據, -->_StreamImplEvents.handleNext() -->最后調用 StreamSubscription.sendData() 給予回調
我學習flutter的整個過程都記錄在里面了
http://www.lxweimin.com/c/36554cb4c804
最后附上demo 地址