Search code examples
firebaseflutterstream-builder

StreamBuilder with flutter_firebase has null value on second widget build (image disappears)


I managed to show images from firestore using streambuilder on a page, but the problem is that the image disappears (I get a null snapshot.data value) if I go back to the last page and come back.

Here is my code. How can I make the snapshot data persist, so the image stays there and doesn't disappear when the widget rebuilds?

Container(child: Column(
      children: [
        Text('    Certifications',
        Container(child: StreamBuilder(
           stream: certificates,
           builder: (context, snapshot) {
             return !snapshot.hasData
              ? Center(child: Container(
                  child: Center(child: Text(
                    'No images yet'))))
              : Container(
                 child: GridView.builder(
                   itemCount: snapshot.data.documents.length,
                   itemBuilder: (context, index) {
                     url = snapshot.data.documents[index].get('url');
                     return Container(child: FadeInImage
                         .memoryNetwork(fit: BoxFit.cover,
                            placeholder: kTransparentImage,
                            image: url),
              ),
            );
         }),
      );
   }),
 ),

Solution

  • Streams are asynchronous. which means StreamBuilder does not get old snapshots, only new future snapshots. This is your problem.

    When your widget is re-built it is subscribing to a stream that has already had events. Yes you would think that data in the snapshot should be the last event value, but that is not the case. It will be null until a new event is pushed onto your certificates stream.

    So one solution is for the service that is loading your certificates to store the value of the initial API request and make that available for you to use in your StreamBuilder's initialData property.

    I would structure it like this:

    StreamBuilder(
        stream: certificateService.stream,
        initialData: certificateService.value, // <-----
        builder: ...
    )
    

    Hope this points you in the right direction.