Search code examples
listviewfluttergoogle-cloud-firestorequeryingstream-builder

ListView doesn't update/get data when using StreamBuilder and Querying from Firebase Firestore database


I'm trying retrieve data from a specific collection users as shown in the code below, but the moment I query for users in this collection, the listview doesn't show up. In other words it just displays a CircularProgressIndicator() signifying there is no data to be found. The moment I comment out the where query, the listview renders perfectly.

        backgroundColor: MyApp.backgroundColor,
        body: StreamBuilder<QuerySnapshot>(
          stream: _firestore
              .collection('users')
//            .where("chapter", isEqualTo: chapter)
              .orderBy('count', descending: true)
              .snapshots(),
          builder: (context, snapshot) {
            if (!snapshot.hasData)
              return Center(child: CircularProgressIndicator());
            return ListView.builder(
              itemExtent: 80.0,
              itemCount: snapshot.data.documents.length,
              itemBuilder: (context, index) =>
                  _buildListItem(context, snapshot.data.documents[index]),
            );
          },
        ),
      );

I've tried to use Nested StreamBuilders and a FutureBuilder in conjunction with a Streambuilder but none of these solutions work. There must be a simple solution to such a crucial feature.

Please advise me on how I can both query and use StreamBuilder together.


Solution

  • As shown in my code snippet below, the trick here is to wrap the StreamBuilder with a FutureBuilder. You need a FutureBuilder if you want to do any querying that involves something that will take time to obtain. In my case, chapter needs to be loaded so that the listview can query for it. The reason the listview wasn't updating with data was because chapter was null when the listview was trying to render.

    Note: If you are querying for something you know ahead of time, there is no need for FutureBuilder. I tested this for a hardcoded chapter, and it works perfectly.

    return FutureBuilder(
            future: _loadChapter(),
              builder: (context, snapshot) {
                return Scaffold(
                  backgroundColor: MyApp.backgroundColor,
                  body: StreamBuilder<QuerySnapshot>(
                    stream: _firestore
                        .collection('users')
                        .where("chapter", isEqualTo: chapter)
                        .orderBy('count', descending: true)
                        .snapshots(),
                    builder: (context, snapshot) {
                      if (!snapshot.hasData)
                        return Center(child: CircularProgressIndicator());
                      return ListView.builder(
                        itemExtent: 80.0,
                        itemCount: snapshot.data.documents.length,
                        itemBuilder: (context, index) =>
                            _buildListItem(context, snapshot.data.documents[index]),
                      );
                    },
                  ),
                );
              }
          );
    

    Here is what the loadChapter method looks like for reference.

     Future<void> _loadChapter() async {
        return await _populateCurrentUser(loggedInUser);
      }
    

    _populateCurrentUser(loggedInUser) essentially finds the document linked with the current logged in user and populates global variables such as the chapter.