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

Flutter Firebase - updating user profile image returns an error while the image change on Firestore


I have an app with a profile page, where I want to have a profile picture, where the user can update whenever he wants.

The code I have now does the following: a StreamBuilder will get the Firestore collection with the Current User UID, and build an Image.network getting the doc "URL" from the snapshot.data.

The problem:

The first time, when the user creates a new user, I have a placeholder on the image, and when the user selects a new image from gallery, it will return an error for the time between updating the collection and updating the UI, and then it changes to the new image. Also, it takes a lot of time to change the image, depending on the size of it.

If someone could give me maybe a different approach on how I am doing, I would appreciate.

The function to upload to Firestore:

File _image;

  Future getImage(bool gallery) async {
    ImagePicker picker = ImagePicker();
    PickedFile pickedFile;
    // Let user select photo from gallery
    if (gallery) {
      pickedFile = await picker.getImage(
        source: ImageSource.gallery,
      );
    }
    setState(() {
      if (pickedFile != null) {
        _image = File(pickedFile.path);
        uploadFile(_image);
        uploadToFirebase(); // Use if you only need a single picture
      } else {
        print('No image selected.');
      }
    });
  }

  Future<String> uploadFile(File image) async {
    String downloadURL;
    Reference ref = FirebaseStorage.instance
        .ref()
        .child("images/${_firebaseAuth.currentUser.uid}");
    await ref.putFile(image);
    downloadURL = await ref.getDownloadURL();
    return downloadURL;
  }

  Future uploadToFirebase() async {
    final CollectionReference users =
        _firebaseFirestore.collection("Companies");
    final String uid = _firebaseAuth.currentUser.uid;

    String url = await uploadFile(
        _image); // this will upload the file and store url in the variable 'url'
    await users.doc(uid).update({'url': url});
    final result = await users.doc(uid).get();
    return result.data()["url"];
  }

The code where I am displaying the image:

Container(
                                child: _image != null
                                    ? Column(
                                        children: [
                                          StreamBuilder(
                                            stream: _firebaseFirestore
                                                .collection("Companies")
                                                .doc(_firebaseAuth
                                                    .currentUser.uid)
                                                .snapshots(),
                                            builder: (BuildContext context,
                                                AsyncSnapshot snapshot) {
                                              if (snapshot.connectionState ==
                                                  ConnectionState.waiting) {
                                                return Text("Loading");
                                              }
                                              return Image.network(
                                                snapshot.data.data()["url"],
                                                width: 100,
                                                height: 100,
                                              );
                                            },
                                          ),
                                        ],
                                      )
                                    : Container(
                                        decoration: BoxDecoration(
                                          color: Colors.grey[200],
                                          borderRadius:
                                              BorderRadius.circular(50),
                                        ),
                                        width: 100,
                                        height: 100,
                                        child: Icon(
                                          Icons.camera_alt,
                                          color: Colors.grey[800],
                                        ),
                                      ),
                              ),

Solution

  • Edit: Can you let me know if this works?

    File _image;
    bool _loading = false;
    final FirebaseStorage _storage = FirebaseStorage(storageBucket:'gs://LINK.com'); //find your link in your storage console like this screenshot https://i.imgur.com/gW35HJk.png
    StorageUploadTask _uploadTask;
    
      Future getImage(bool gallery) async {
        this.setState((){
        _loading = true;
        });
        ImagePicker picker = ImagePicker();
        PickedFile pickedFile;
        // Let user select photo from gallery
        if (gallery) {
          pickedFile = await picker.getImage(
            source: ImageSource.gallery,
          );
        }
        setState(() {
          if (pickedFile != null) {
            _image = File(pickedFile.path);
            uploadFile(_image);
          } else {
            print('No image selected.');
            this.setState((){
            _loading = false;
            });
    
          }
        });
      }
    
      Future<String> uploadFile(File image) async {
        String downloadURL;
        String filePath = "images/${_firebaseAuth.currentUser.uid}";
        setState(() {
          _uploadTask = _storage.ref().child(filePath).putFile(image).onComplete;
        });
        var imageUrl = await (await 
        _uploadTask.onComplete).ref.getDownloadURL();
        downloadURL = imageUrl.toString();
        
        uploadToFirebase(downloadURL);
      }
    
      Future uploadToFirebase(downloadURL) async {
        final CollectionReference users =
            _firebaseFirestore.collection("Companies");
        final String uid = _firebaseAuth.currentUser.uid;
    
        String url = downloadURL // this will upload the file and store url in the variable 'url'
        await users.doc(uid).update({'url': url});
        final result = await users.doc(uid).get();
    
        if (result != null) {
           setState((){
                getImage().onComplete{
                loading = false;
           }
           return result.data()["url"];
        }
        });
      }
    
    ----------Below is before edit---------------
    
    Use a bool to determine if loading is complete or not
    
    bool _loading = false;
    
        Future getImage(bool gallery) async {
            this.setState((){
            _loading = true;
            });
        
            ImagePicker picker = ImagePicker();
            PickedFile pickedFile;
            // Let user select photo from gallery
            if (gallery) {
              pickedFile = await picker.getImage(
                source: ImageSource.gallery,
              );
            }
            setState(() {
              if (pickedFile != null) {
                _image = File(pickedFile.path);
                uploadFile(_image);
                uploadToFirebase(); // Use if you only need a single picture'
         setState(() {
              _loading = false;
            });
              } else {
                print('No image selected.');
                setState(() {
              _loading = false;
            });
              }
            });
          }