Pieter Pienaar
Pieter Pienaar

Reputation: 178

Flutter Firestore excessive reads

I am creating an app to show the latest fuel price for the users, and I'm using a snapshot listener on my Firebase Firestore database, and per my understanding it should create 1 read per user only when I update the database... I have it installed on 1 device, and get 33 reads for that one device!

The code that connects to Firebase is:

    StreamBuilder<DocumentSnapshot>(
                                    stream: FirebaseFirestore.instance
                                        .collection('global')
                                        .doc('inland')
                                        .snapshots(),
                                    builder: (context, snapshot) {
                                      if (!snapshot.hasData) {
                                        return Text("Loading...",
                                            style: TextStyle(
                                                color: Colors.black,
                                                fontWeight: FontWeight.w700,
                                                fontSize: 34.0));
                                      }
                                      if (snapshot.hasError) {
                                        return Text("Error",
                                            style: TextStyle(
                                                color: Colors.black,
                                                fontWeight: FontWeight.w700,
                                                fontSize: 34.0));
                                      }
                                      if (snapshot.connectionState ==
                                          ConnectionState.waiting) {
                                        return Text("Loading...",
                                            style: TextStyle(
                                                color: Colors.black,
                                                fontWeight: FontWeight.w700,
                                                fontSize: 34.0));
                                      } else {
                                        Map<String, dynamic> document =
                                            snapshot.data.data();
                                        return Text("R " + document['95'],
                                            style: TextStyle(
                                                color: Colors.black,
                                                fontWeight: FontWeight.w700,
                                                fontSize: 34.0));
                                      }

It is in an AnimatedContainer, but as I understand it, the app shows the price from cache when it doesn't change on the database, so this shouldn't make a difference.

Am I understanding something wrong? And is there a way to fix this?

Upvotes: 1

Views: 1614

Answers (1)

osaxma
osaxma

Reputation: 2984

You're creating the stream every time flutter calls the build method of that widget, which can be a lot of times. The build method should be pure without any side effects*. In other words, you shouldn't instantiate expensive objects such as stream inside the build method. You should create the object outside, and pass it to the the widget.

To solve this issue, you could create a stateful widget, and inside the initState method, you should initialize your stream and then pass it to the StreamBuilder.

class StreamBuilderExample extends StatefulWidget {
  @override
  _StreamBuilderExampleState createState() => _StreamBuilderExampleState();
}

class _StreamBuilderExampleState extends State<StreamBuilderExample> {
  Stream<DocumentSnapshot> firestoreStream;
  @override
  void initState() {
    firestoreStream = FirebaseFirestore.instance.collection('global').doc('inland').snapshots();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: firestoreStream,
      builder: (context, snapshot) {
        // your code goes here
      },
    );
  }
}

For the last bit of your question, Firestore will only read from cache if you tell it to do so or if there's no internet connection. Every time you initiate a stream or get documents, Firestore will reach the server first and re-read the documents again. Though when the stream is running, Firestore will only update when there are changes to the documents of your query. But as mentioned before, you're getting many reads because your stream was being recreated every time the widget is being built (this can also be caused by the hot-reload or simply saving the file).

Upvotes: 3

Related Questions