Search code examples
flutterdartstream-builder

Flutter StreamBuilder removes old data while loading


Currently I have a StreamBuilder pulling data from Firebase for a group messaging app. I have a snapshot.hasData check to make sure that there is data before displaying the messages. The problem is that when setState rebuilds the widgets, it also rebuilds the StreamBuilder causing it to display the static snapshot.hasData == false content before it finishes loading the data again. This looks really bad because it loads so fast that it just looks like the screen is flickering for a second every rebuild.

How would I go about retaining the data while it reloads itself, so it does not appear to flicker?

Is there a way I can prevent the StreamBuilder from rebuilding given specific circumstances?

Thanks!

Edit added current code.

var firebaseStream;
  @override
  void initState() {
    super.initState();
    firebaseStream = Firestore.instance
        .collection('groups')
        .document(groupID)
        .collection('messages')
        .orderBy('date', descending: true)
        .limit(15)
        .snapshots();

StreamBuilder(
  stream: firebaseStream,
  builder: (context, snapshot) {
     if (!snapshot.hasData)
        return Container(
           color: Colors.red,);
        return ListView.builder(

Solution

  • It sounds as if you're fetching the data directly in the StreamBuilder stream property:

    StreamBuilder(
      stream: firebase.getData(),
      ...
    )
    

    The problem with this is it will create a new stream every time setState is called and always give an initial null value. Instead, you should use a StatefulWidget and create a variable in your state during initState, so that it only runs once. Then use this variable as your stream property in the StreamBuilder. Here's a very simple example:

    class Example extends StatefulWidget {
      Example({Key key}) : super(key: key);
    
      @override
      _ExampleState createState() => _ExampleState();
    }
    
    class _ExampleState extends State<Example> {
      Stream firebaseData;
    
      @override
      void initState() {
        super.initState();
        firebaseData = Firebase.fetchData(); //Or whatever function you use
      }
    
      @override
      Widget build(BuildContext context) {
        return StreamBuilder(
          stream: firebaseData,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (snapshot.hasData) {
              return Text(snapshot.data);
            } else {
              return Loading();
            }
          },
        );
      }
    }