Search code examples
fluttergoogle-cloud-firestorefirebase-storagestream-builder

Why is the Streambuilder not updating the UI?


I am uploading an image, then storing it in Firebase Storage, and then store the link in the Firebase database. I have added a Streambuilder to update the UI. However, I am getting a never ending circular progress bar when I do that. I am sure there is something wrong with my Streambuilder code.

Firebase Database Screenshot

Code snippet as follows:

class EditProfile extends StatefulWidget {
  const EditProfile({
    super.key,
    required this.userData,
  });
  final UserModel userData;

  @override
  State<EditProfile> createState() => _EditProfileState();
}

class _EditProfileState extends State<EditProfile> {
.....

StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
                      stream: FirebaseFirestore.instance
                          .collection('users')
                          .snapshots(),
                      builder: (context, snapshot) {
                        if (snapshot.hasData) {
                          return CircleAvatar(
                            radius: 75,
                            backgroundImage: NetworkImage(
                                widget.userData.profileImage.toString()),
                          );
                        } else {
                          return const CircularProgressIndicator();
                        }
                      }),

Please let me know where should I make the code changes. Variable values using breakpoint at if (error)


Solution

  • The problem is probably due to how the StreamBuilder is handling different states of the snapshot.

    The CircularProgressIndicator appears running constantly because there is no proper handling for the connection state, errors, and empty data cases.

    specifically, the problem might be in your code, you are doing:

     if (snapshot.hasData) { // ---> Only if there's data
          return CircleAvatar(
            radius: 75,
            backgroundImage: NetworkImage(widget.userData.profileImage.toString()),
          );
        } else {
           // --> if there's no data or loading
          return const CircularProgressIndicator();
        }
    

    which means, only if there are actual documents (e.g, .hasData) will it show the CircleAvatar.

    Instead, you can use, which will account for all correct loading states and if there's data (documents):

    StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
      stream: FirebaseFirestore.instance.collection('users').snapshots(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const CircularProgressIndicator();
        } else if (snapshot.hasError) {
          print(snapshot.error); // --> Debug the error here
          return const Text('Something went wrong');
        } else if (!snapshot.hasData || snapshot.data!.docs.isEmpty) {
          return const Text('No data available');
        } else {
          return CircleAvatar(
            radius: 75,
            backgroundImage: NetworkImage(widget.userData.profileImage.toString()),
          );
        }
      },
    ),
    

    Note: If there's an error (which might be your case), it will show the text "Something went wrong" - which you'll have to debug (I added print(snapshot.error) ).