StreamBuilder is not rebuilding on new event in stream
Asked Answered
R

2

3

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?

Regulate answered 23/5, 2019 at 15:17 Comment(3)
Try testing by adding your print statement inside StreamBuilder. AFAIK it doesn't force the entire widget to rebuild.Rafaelle
I am ssuming that you're using rxDart so tell me something what kind of stream controller are you using? PublishSubject or BehaviorSubject?Conjunctiva
It's BehaviourSubject @MarcosBoaventuraConcentrated
R
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.

Regulate answered 27/5, 2019 at 9:34 Comment(0)
K
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,
}
Keim answered 23/5, 2019 at 23:54 Comment(2)
Unfortunately, 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...Concentrated
Streams 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?Keim
R
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.

Regulate answered 27/5, 2019 at 9:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.