StreamBuilder is not rebuilding on new event in stream
Solution 1
The issue was I was instantiaing my BLOC incorrectly(second one) and working on a second parallel stream and therefore not the one passed to StreamBuilder.
Solution 2
Your bloc needs to be a type of Stream. The same stream type as your StreamBuilder. For example your bloc needs to be a Stream<Alarm>
. Otherwise stream: widget.bloc.alarmController.stream,
will only be called once and won't act as an asynchronous stream of data.
Your Streambuilder needs to check for connection states
Widget build(BuildContext context) {
print("rebuilding..."); // as of now this gets called only on view initialization and never again - i.e. not on new events going through alarmController.stream
return StreamBuilder<Alarm>(
stream: widget.bloc.alarmController.stream,
initialData: Alarm(''),
builder: (BuildContext context, AsyncSnapshot<Alarm> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading...');
default:
if (!snapshot.hasData) {
return Center(
child: Text(StringLiterals.NO_ALARM_DATA_MSG))
);
}
return Switch(
activeColor: Colors.red,
value: snapshot.data.status == 'Started',
onChanged: (bool _value) {
_newAlarmValue = _value;
_askAlarmConfirmation();
}));
}
Here are the other types of connection states you can check for:
async.dart
enum ConnectionState {
/// Not currently connected to any asynchronous computation.
///
/// For example, a [FutureBuilder] whose [FutureBuilder.future] is null.
none,
/// Connected to an asynchronous computation and awaiting interaction.
waiting,
/// Connected to an active asynchronous computation.
///
/// For example, a [Stream] that has returned at least one value, but is not
/// yet done.
active,
/// Connected to a terminated asynchronous computation.
done,
}
Alan Kałuża
Updated on December 11, 2022Comments
-
Alan Kałuża over 1 year
My StreamBuilder in view:
Widget build(BuildContext context) { print("rebuilding..."); // as of now this gets called only on view initialization and never again - i.e. not on new events going through alarmController.stream return StreamBuilder( stream: widget.bloc.alarmController.stream, initialData: Alarm(''), builder: (BuildContext context, AsyncSnapshot<Alarm> snapshot) { if (!snapshot.hasData) { return Center( child: Text(StringLiterals.NO_ALARM_DATA_MSG)) ); } return Switch( activeColor: Colors.red, value: snapshot.data.status == 'Started', onChanged: (bool _value) { _newAlarmValue = _value; _askAlarmConfirmation(); })); }); }
meat of my bloc:
AlarmBloc(this.Api) { getAlarm(); } getAlarm() async { Alarm response = await Api.getAlarmStatus(); alarmController.sink.add(response); // here im adding new event, therefore streambuilder should rebuild, right? }
And lastly the code I call to initiate new event(in this case it's firebase message):
if(_message.notification.body.contains("Alarm") && IS_LOGGED_IN == true) { alarmBloc.getAlarm(); }
So the problem is StreamBuilder not rebuilding whenever new event passes through alarmController.stream. What could be the reason?
-
Mazin Ibrahim almost 5 yearsTry testing by adding your print statement inside
StreamBuilder
. AFAIK it doesn't force the entire widget to rebuild. -
Marcos Boaventura almost 5 yearsI am ssuming that you're using rxDart so tell me something what kind of stream controller are you using? PublishSubject or BehaviorSubject?
-
Alan Kałuża almost 5 yearsIt's BehaviourSubject @MarcosBoaventura
-
-
Alan Kałuża almost 5 yearsUnfortunately, this isn't the case. The connection is not being terminated and even with StreamBuilder type given it's still not rebuilding the widget on new event being added to sink...
-
Val almost 5 yearsStreams can be tricky. There are more options we can check out for you. We would need to reconfigure the calling stream in place of sending the 'response' back through the controller. It looks like the getAlarm is only getting call on the build and isn't streaming data back asynchronously. First can you tell me what type of response Type you are expecting from getAlarm?