Search code examples
flutterasync-awaitflutter-riverpod

Flutter Riverpod StreamProvider not waiting for for loop to finish before building Widget


I have a StreamProvider here:

final secondTabProvider = StreamProvider((ref){
  EmergencyContactsController contacts = EmergencyContactsController(currentUserID: ref.read(authProvider).currentUser!.uid);
  return contacts.getUserEmergencyContacts();
});

And I call it in my build method like so:

_secondTab.when(
  data: (data) {
    if (!data.exists){
     return Text("no data")
    }

    Map<String, dynamic doc = data.doc() as Map<String, dynamic>;
    
    List conversations = doc['conversation'];

    // Store the user profiles
    List<EmergencyContactModel> users = [];

    for (Map<String, dynamic> user in userConversations){
                              
      contacts.getContactInfo(
       uid: user['userID']
      ).then((value){
        if (value != null){
         EmergencyContactModel contact = EmergencyContactModel.fromJson(value);

         contact.messageID = value["id"] + ref.read(authProvider).currentUser!.uid;
         users.add(contact);
        }

      });
    }

   return Listview.builder(
    itemCount: users.length,
    itemBuilder: (BuildContext context, int index) => Text(users[index]['name'])
   );
  },
  error: (err, _){
   return Text("Error")
  },
  loading: () => CircularProgressIndicator()

)

The contacts.getContactInfo() method is an async and I need it to execute before the loop continues to the next iteration, but it's not doing that. Any help would be largely appreciated.


Solution

  • I solved it. I converted the for loop into its own async function as seen below:

    // Generate a list of users that the current user has had conversations with
      userinfoGenerator(List userIDs) async {
        // Get the user profiles
        List<EmergencyContactModel> users = [];
    
        for (Map<String, dynamic> user in userIDs){
         
          Map<String, dynamic>? contactInfo = await contacts.getContactInfo(uid: user['userID']);
    
          if (contactInfo != null){
            EmergencyContactModel contact = EmergencyContactModel.fromJson(contactInfo);
            contact.messageID =  contactInfo["id"] + ref.read(authProvider).currentUser!.uid;
            users.add(contact);
          }
    
        }
    
        return users;
      }
    

    And then I used a Future Builder to return the result of the function as seen below:

    return FutureBuilder(
        future: userinfoGenerator(userConversations),
        builder: (BuildContext context, AsyncSnapshot snapshot){
    
          // Checking if future is resolved
          if (snapshot.connectionState == ConnectionState.done) {
            // If we got an error
            if (snapshot.hasError) {
              return Center(
                child: CustomText(
                  label: '${snapshot.error} occurred',
                ),
              );
    
              // if we got our data
            } else if (snapshot.hasData) {
              // Extracting data from snapshot object
              final data = snapshot.data;
              return ListView.builder(
                  shrinkWrap: true,
                  itemCount: data.length,
                  itemBuilder: (BuildContext context, int index) {
                    List<String> theName = data[index].name
                        .split(" ");
                    return Padding(
                      padding: const EdgeInsets.only(
                          top: 12.0),
                      child: CustomListTile(
                          contact: data[index],
                          label: theName.length == 1
                              ? theName[0][0]
                              : "${theName[0][0]} ${theName[theName
                              .length - 1][0]}"
                      ),
                    );
                  }
              );
            }
          }
    
          return const Center(
            child: CircularProgressIndicator(
              color: kDefaultBackground,
            ),
          );
        },
      );