This solves my problem where I always get the error "Bad state: Stream has been listened to". I don't want to use broadcasting because I read that it accumulates instances and then it will affect performance and so... here's my solution. The point here is that when I listen to a single stream, it should close the listening by itself when I move to another page, just to prevent that error. I'm not a genius coder, but this is what I have come up with. If you're here because we have the same problem, then I hope this can help you.
- Declare your streams and your variables in your provider.
class UserProvider with ChangeNotifier {
StreamController<List<User>> myStream;
List<User> _listData = []
}
- Add a function that will fetch your stream, for example like this:
Stream getAllDataStream() {
myStream = StreamController<List<User>>();
if (_listData.isNotEmpty) myStream.add(_listData);
return myStream.stream;
}
- In your stateful/stateless widget create the provider instance in
initState()
then start listening in the build, like this:
UserProvider provider;
Stream<dynamic> userStream;
@override
void initState() {
super.initState();
provider =
Provider.of<UserProvider>(context, listen: false);
}
@override
Widget build(BuildContext context) {
userStream = provider.myStream == null
? provider.getAllDataStream()
: provider.myStream.stream;
}
- Add a close function in your provider, close your stream and set it to null in the
whenComplete()
function, as shown below:
Future<void> closeStream() async {
await myStream
.close()
.whenComplete(() => myStream = null);
}
- Lastly call this
closeStream()
in thedeactivate()
method.
@override
void deactivate() async {
await provider.closeStream();
super.deactivate();
}