skip to Main Content

I have the below code, where a FutureBuilder loads some data that is a Map<String, dynamic>. While the FutureBuilder is loading, it returns a loading spinner. After the future completes with the data, it returns a StreamBuilder that listens to a Firestore query. The print statements output the following in the console:

Future build: {'abc': {'type': 1, 'color': 'red'}, 'def': {'type': 2, 'color': 'blue'}}
Stream build: {'abc': {'type': 1, 'color': 'red'}, 'def': {'type': 2, 'color': 'blue'}}
Stream build 2: {'abc': {'type': 1, 'color': 'red'}, 'def': {'type': 2, 'color': 'blue'}}
Stream build: {'abc': {'type': 1, 'color': 'red'}, 'def': {'type': 2, 'color': 'blue'}}
Stream build 2: {'abc': {'type': 1, 'color': 'red'}, 'def': {'type': 2, 'color': 'blue'}}
Stream build 3: {'abc': {'type': 1, 'color': 'red'}}
return FutureBuilder(
    future: _future,
    builder: (context, snapshot) {
      if (!snapshot.hasData) {
        return const Center(
          child: CircularProgressIndicator(),
        );
      }

      final info = snapshot.data;

      print('Future build: $info');

      return StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
        stream: _stream,
        builder: (context, AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snap) {
          print('Stream build: $info');

          if (snap.hasError) {
            return const Center(
              child: Text('An error occurred.'),
            );
          }

          print('Stream build 2: $info');

          if (!snap.hasData) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }

          print('Stream build 3: $info');
        });
      });

My question is, how is the second element of the Map getting deleted on the second build of the StreamBuilder? The variable is even final! There are no other places in the code where the info variable is set, and no other variables sharing that name.

I understand why the StreamBuilder builds twice, and on the first build does not reach the Stream build 3 print. But I cannot understand why it would be modifying the variable set by the previous FutureBuilder.

2

Answers


  1. Your problem is simple, but your question is bullshit :/ honestly.

    In case you using 2 same thing, but low-diff. Here is the different:

    FutureBuilder has a single AsyncSnapshot that represents the current state of the Future, while StreamBuilder has multiple AsyncSnapshots, each representing a new piece of data emitted by the Stream. FutureBuilder will execute the Future every time the widget is rebuilt, while StreamBuilder will only subscribe to the Stream once when the widget is mounted, and unsubscribe when the widget is disposed.

    You can see here, Your FutureBuilder widget is parent of StreamBuilder. When you change your online data, StreamBuilder will setState the entire widget.

    Because of that, FutureBuilder is restarted and the above info variable is updated twice.

    Just choose right widget in your case.

    If you want to listen to all the changes from the server as a stream, you should use StreamBuilder, but if you want to call it once, the variable will not be announced inside the widget, but if it is announced outside, StreamBuilder will not be able to affect it.

    Finally, if you use StreamBuilder, I recommend not including it in FutureBuilder. Also you have to see other peoples solution, maybe they have found a way. Cheer

    Login or Signup to reply.
  2. Did you override the toString method of your info class to modify something?

    Or did you not include the full code, or the complete logs?

    Because otherwise there is no way that the code

              print('Stream build 2: $info');
    
              if (!snap.hasData) {
                return const Center(
                  child: CircularProgressIndicator(),
                );
              }
    
              print('Stream build 3: $info');
    

    leads to this output:

    Stream build 2: {'abc': {'type': 1, 'color': 'red'}, 'def': {'type': 2, 'color': 'blue'}}
    Stream build 3: {'abc': {'type': 1, 'color': 'red'}}
    

    That would not be possible in dart.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search