I have a StreamBuilder that I want to be able to pause and unpause and, since StreamBuilder doesn't expose it's underlying StreamSubscription, I have to create a proxy stream to forward the source stream's elements while exposing a StreamSubscription that I can pause and unpause. This forces me to convert my stateless widget into a stateful widget so I have access to dispose and can close it's StreamController.
I'm following the didUpdateWidget documentation's instructions:
In initState, subscribe to the object. In didUpdateWidget unsubscribe from the old object and subscribe to the new one if the updated widget configuration requires replacing the object. In dispose, unsubscribe from the object.
I need to replace the Stream whenever the user types in a new search query. My stateful widget is re-constructed within a ChangeNotifier whenever a new stream is received.
Here's the relevant part of my stateful widget:
final Stream<List<Entry>> _entryStream;
StreamController<List<Entry>> _entryStreamController;
StreamSubscription<List<Entry>> _entryStreamSubscription;
_EntryListState(this._entryStream);
void initStream() {
_entryStreamController?.close();
_entryStreamController = StreamController();
_entryStreamSubscription = _entryStream.listen((event) {
_entryStreamController.add(event);
}
)..onDone(() => _entryStreamController.close());
}
@override
void initState() {
initStream();
super.initState();
}
@override
void dispose() {
_entryStreamController?.close();
super.dispose();
}
@override
void didUpdateWidget(EntryList oldEntryList) {
// Initialize the stream only if it has changed
if (oldEntryList._entryStream != _entryStream) initStream();
super.didUpdateWidget(oldEntryList);
}
This is the line throwing the BadState error:
_entryStreamSubscription = _entryStream.listen((event) {
_entryStreamController.add(event);
}
And here is where my widget is being constructed:
child: Consumer<SearchStringModel>(
builder: (context, searchStringModel, child) {
print('rebuilding with: ${searchStringModel.searchString}');
var entryStream = _getEntries(searchStringModel.searchString);
return EntryList(entryStream);
}
),
I don't think I understand didUpdateWidget in particular and suspect that's where the two issues (bad state, and not updating) are coming from? I'm also re-constructed the stateful widget instead of just modifying its state which is a little confusing, but the widget is intended to act as a stateless widget for all intents and purposes so it'd be a pain to update it to update state instead of reconstructing. Any advice?