Flutter: StreamBuilder does not show data on connection.state.active

Issue

I been trying to figure this out for the entire weekend so I finaly decided to ask you for your advice.

Got a streambuilder which listens for a stream or recipes (filtered by the category -> soups, deserts etc.).

I were confused because the Text "Nothing" (last return statement) was the only thing showing, even though my print statements in the if condition, which asks for the connectionstate.active shows me all the values.

When I print the connection state out one line above my text widget "Nothing" I get "active".

Of course I could just get rid of my if statement and put the returning widget at the end, but I would like to know and understand, why my return statement in my .active condition does not show me the column etc. even though the print statements are shown in the console.

Btw I saw alot of other resources were a Listview is used but I am not sure weather or not I can use a Listview together with a stack (because I want to show data on top of each other).

Looking forward to your replys!

Regards
Thomas

new StreamBuilder<QuerySnapshot>(
                    stream: FirebaseFirestore.instance.collection("rezepte").where("kategorie", isEqualTo: ausgewaehlteKategorie).snapshots(),
                    builder: (context, AsyncSnapshot<QuerySnapshot> snapshot){
                      print("***** STREAMBUILDER *****");
                      if (snapshot.connectionState == ConnectionState.waiting) {
                        print(snapshot.connectionState);
                        return CircularProgressIndicator();
                      }
                      
                      if(snapshot.connectionState == ConnectionState.active){
                        print(snapshot.connectionState);
                        print(snapshot.data!.docs);
                        print(snapshot.data!.docs[0]["name"]);
                        print(snapshot.data!.docs[0]["kategorie"]);

                        print(snapshot.data!.docs.length);

                        snapshot.data!.docs.map((docs){
                          print("Test1");
                          listeAllerRezepte.add(
                            Rezept(
                              name: docs["name"].toString(),
                              kategorie: docs["kategorie"].toString(),
                              naehrwertKohlenhydrate: docs["naehrwertKohlenhydrate"],
                              naehrwertFett: docs["naehrwertFett"],
                              naehrwertEiweiss: docs["naehrwertEiweiss"],
                              naehrwertKohlenhydrateProzent: double.parse((100 / (docs["naehrwertKohlenhydrate"] + docs["naehrwertFett"] + docs["naehrwertEiweiss"]) * docs["naehrwertKohlenhydrate"]).toStringAsFixed(2)),
                              naehrwertFettProzent: double.parse((100 / (docs["naehrwertKohlenhydrate"] + docs["naehrwertFett"] + docs["naehrwertEiweiss"]) * docs["naehrwertFett"]).toStringAsFixed(2)),
                              naehrwertEiweissProzent: double.parse((100 / (docs["naehrwertKohlenhydrate"] + docs["naehrwertFett"] + docs["naehrwertEiweiss"]) * docs["naehrwertEiweiss"]).toStringAsFixed(2)),
                              img: docs["img"],
                              favorit: docs["favorit"]
                            )
                          );
                          print("Test2");

                          print(listeAllerRezepte[0]);
                          print(listeAllerRezepte[0].name.toString());
                          print(listeAllerRezepte[0].kategorie.toString());
                          print(listeAllerRezepte[0].img.toString());

                          return new Column(
                            children: [
                              new Stack(
                                alignment: Alignment.bottomCenter,
                                children: [
                                  new Text("Test1"),
                                  new Container(
                                    child: new GestureDetector(
                                      child: new Column(
                                        children: [
                                          new Text("TEST"),
                                          new Image(
                                            image: (docs["img"].toString().length > 0) ? NetworkImage(docs["img"].toString()) : NetworkImage(globals.listeAllerKategorien![nummerAusgewaehleKategorie].img.toString())
                                          ),
                                        ],
                                      ),
                                      onTap: () {
                                      },
                                    ),
                                  ),
                                  new Divider(height: 100.0)
                                ],
                              ),
                              new Divider(height: 15.0)
                            ]
                          );
                        }).toList();
                      }

                      if(snapshot.connectionState == ConnectionState.done){
                        print(snapshot.connectionState);
                      }
                      
                      if(!snapshot.hasData){
                        return Text("Loading");
                      }

                      return new Text("Nothing");
                    }
                  )

Solution

Once the StreamBuilder has recieved all of the data and a done signal, the state becomes done. It does not sit there in there in active. Your checks should go is waiting, has data, and a catch all afterwards for no data.

UPDATE: The issue is in your return statement in the if(snapshot.connectionState == ConnectionState.active) block. You are not actually returning a widget from the block, so the function is continuing until it reaches the final return statement.

First, make this if statement if(snaphsot.hasData). Then take a look at this section:

snapshot.data!.docs.map((docs){
  ...
  return new Column(
  ...
}

Here, your return statement is to the anonymous function passed to the map method. The Columns are not being returned out of the builder.

While I am not quite sure what your needs are, I believe some of your widgets are nested improperly as well. Below is my best guess at what you are going for, please adjust accordingly. (I have left out some of your code for brevity, focusing only on building the widgets causing your issues.)

if(snapshot.hasData){
  return new Column(
    children: snapshot.data!.docs.map((docs){
      return new Stack(
       alignment: Alignment.bottomCenter,
       children: [
         new Text("Test1"),
         new Container(
           child: new GestureDetector(
             child: new Column(
               children: [
                 new Text("TEST"),
                 new Image(
                   image: (docs["img"].toString().length > 0) ? NetworkImage(docs["img"].toString()) : NetworkImage(globals.listeAllerKategorien![nummerAusgewaehleKategorie].img.toString())
                 ),
               ],
             ),
             onTap: () {},
           ),
         ),
         new Divider(height: 100.0)
       ],
     );
   },
 );
}

NOTE: A ListView is certainly capable of providing what you need, and it is a much better option than Column. It provides scrolling out of the box, better performance and memory usage, as well as some handy constructors that can provide a Divider where needed. I encourage you to check it out once you are comfortable with these results.

Answered By – Lee3

Answer Checked By – Mary Flores (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *