share & LiveValue.from
One run of a chain, many listeners — and the version that remembers its latest value for whoever arrives late.
Lecture
Every operator in this section builds its own
StreamController, so the chain it returns is
single-subscription: listen to it twice and the
second listener gets a StateError. That default is
deliberate — it keeps the chain cold, so nothing runs until someone
consumes it, and it keeps per-listener state honest. But it means two
widgets cannot watch the same debounced, throttled, switch-mapped
feed without building it twice.
share() fixes that. It connects on the
first listener and broadcasts to every listener from
there, so the work upstream happens once no matter how many are
watching. A debounce timer, a socket, an expensive map — one of each,
not one per subscriber.
share({reset: true}) — the default — now matches Rx's
ref-count reset. When the last listener leaves
before the source has completed, the upstream
subscription is cancelled and the next listener starts a fresh
subscribe. After the source completes, a later
listener is still handed a closed stream.
share(reset: false) is the 0.8.7 behaviour: the last
cancel closes forever. A resubscribe needs a source that allows a
second listen — Stream.fromIterable,
Stream.multi, FxEvents.defer, a
broadcast — a spent single-subscription
StreamController still cannot be re-listened. Attach
every listener before the first event if the source is one-shot,
or keep one alive.
share() also does not remember: a listener that
arrives after an event has passed has simply missed it. For a window
of history, shareReplay
is the next page. When latecomers need the current state — which is
most UI —
LiveValue is the answer, and
LiveValue.from(source) / LiveValue.seededFrom(seed,
source) build one directly from a stream. Those are
hot: the subscription opens immediately, so values
arriving before anyone listens still update
value, and close() cancels the source. They
are named constructors rather than an optional seed so that a nullable
T can still be seeded with null. fxdart events layer,
after Rx's share and shareValue.
Demo 1 · Why one listener is the default
Demo 2 · One run, two listeners
Try it yourself
Exercise: a LiveValue fed straight from a stream.
shareReplay — multicast that remembers a buffer of history ·
LiveValue — the sharing that remembers: late subscribers get the current value first ·
tee — the pull-side answer to two readers over one pass, with no buffer ·
fork — two independent pull cursors over one source, at the cost of a buffer