Flutter : Bad state: Stream has already been listened to
You could use broadcast
, which allows to listen stream more than once, but it also prevents from listening past events:
Broadcast streams do not buffer events when there is no listener.
A better option is to use BehaviorSubject
from rxdart
package class as StreamController
. BehaviorSubject
is:
A special StreamController that captures the latest item that has been added to the controller, and emits that as the first item to any new listener.
The usage is as simple as:
StreamController<...> _controller = BehaviorSubject();
In my case, I was getting this error because the same line of code myStream.listen()
was being called twice in the same widget on the same stream. Apparently this is not allowed!
UPDATE: If you intend to subscribe to the same stream more than once, you should use a behavior subject instead:
// 1- Create a behavior subject
final _myController = BehaviorSubject<String>();
// 2- To emit/broadcast new events, we will use Sink of the behavior subject.
Sink<String> get mySteamInputSink => _myController.sink;
// 3- To listen/subscribe to those emitted events, we will use Stream (observable) of the behavior subject.
Stream<String> get myStream => _myController.stream;
// 4- Firstly, Listen/subscribe to stream events.
myStream.listen((latestEvent) {
// use latestEvent data here.
});
// 5- Emit new events by adding them to the BehaviorSubject's Sink.
myStreamInputSink.add('new event');
That's it!
However, there is one final important step.
6- We must unsubscribe from all stream listeners before a widget is destroyed.
Why? (You might ask)
Because if a widget subscribes to a stream, and when this widget is destroyed, the destroyed widget stream subscription will remain in app memory causing memory leaks and unpredictable behavior.:
_flush() {
_myController.close();
_myController = StreamController<String>();
}
############################### ###############################
Old Answer:
What fixed it for me is to both create a my stream controller as a broadcast stream controller:
var myStreamController = StreamController<bool>.broadcast();
AND
use stream as a broadcast stream:
myStreamController.stream.asBroadcastStream().listen(onData);
The most common form of Stream
can be listened only once at a time. If you try to add multiple listeners, it will throw
Bad state: Stream has already been listened to
To prevent this error, expose a broadcast Stream
. You can convert your stream to a broadcast using myStream.asBroadcastStream
This needs to be done inside your class that expose Stream
. Not as parameter of StreamBuilder
. Since asBroadcastStream
internally listen to the original stream to generate the broadcast one, this imply you can't call this method twice on the same stream.
You should use the following.
StreamController<...> _controller = StreamController<...>.broadcast();