flutter, trying to update a picture from Storage

583

Here when the image is picked you should directly set it or you can set it after the firebase upload is finished successfully.

But rather than loading an image from Firebase URL after the upload, you can directly load from the picked file as follows;

image = Image.memory(await pickedFile.readAsBytes())

This will instantly set the image and will save you a read call to Firebase. You should always try to minimize the Firebase Reads whenever possible.

Share:
583
Sharki
Author by

Sharki

Updated on December 12, 2022

Comments

  • Sharki
    Sharki over 1 year

    I'm trying to upload, and update a picture from firebase storage. But for some reason this is not working properly.

    This would be the scenario; A user take a picture from his camera, so this picture is uploaded to my storage, so after that I get the url picture, so I can use this like NetworkImage(url) to update the picture.

    This is what's happening currently:


    Let's say I don't have any picture.

    • I update my profile with a new picture. (This works perfectly).

    Now let's say I want to update my profile picture, so I take another picture, let's call it A so I upload this one.

    • Nothing happens, picture doesn't change.

    But If I try again with a B picture, for some reason the picture is updated with the A picture.


    This would be my code and how I'm facing this feature.

    I have the next method which is invoked when a user click over his picture. I wait for the result (value) so when I got the result I upload the picture. Then, when the picture is uploaded, I just call to setState and save the url into the _imageUrl variable.

    After that, I change the "profilePic" attribute from my data base to true.

      String _imageUrl = 'assets/profileDefault.jpg';
      bool profilePicture = false;
      io.File profilePic;
      Future getFromCamara() async {
        await ImagePicker().getImage(source: ImageSource.camera).then((value) {
          profilePic = io.File(value.path);
          FirebaseStorage.instance.ref().child('picture').putFile(profilePic);
        }).then((result) {
          var ref = FirebaseStorage.instance.ref().child('picture');
          ref.getDownloadURL().then((loc) => setState(() => _imageUrl = loc));
        });
    
        try {
          FirebaseFirestore.instance
              .collection('Usuarios')
              .doc(uid)
              .update({'profilePic': true});
        } catch (e) {
          print(e.toString());
        }
    

    So now, using a StreamBuilder, I get the result of profilePic from my DataBase, if is True, I download the URL, and if don't, I just use the Asset default's pic.

    body: StreamBuilder(
            stream: FirebaseFirestore.instance.collection('Usuarios').snapshots(),
            builder: (context, AsyncSnapshot<QuerySnapshot> snapshot1) {
    
                  if (!snapshot1.hasData) {
                    return Center(
                      child: CircularProgressIndicator(),
                    );
                  }
    
                  List<DocumentSnapshot> users = snapshot1.data.docs;
    
                  for (DocumentSnapshot user in users) {
                    if (user.id == userID) {
                      profilePicture = user['profilePic'];
                    }
                  }
    
                  if (profilePicture) {
                    FirebaseStorage.instance
                        .ref()
                        .child('picture')
                        .getDownloadURL()
                        .then((loc) => _imageUrl = loc);
                  } else {
                    _imageUrl = 'assets/profileDefault.jpg';
                  }
                 
                  return Stack(
                    alignment: Alignment.center,
                    children: <Widget>[
                      Positioned(
                        top: 0,
                        child: Container(
                          color: Color.fromRGBO(255, 0, 0, 70),
                          width: MediaQuery.of(context).size.width,
                          height: MediaQuery.of(context).size.height * .55,
                        ),
                      ),
                      Positioned(
                        top: MediaQuery.of(context).size.height * .015,
                        left: 15,
                        right: 15,
                        child: Container(
                          width: MediaQuery.of(context).size.height * .90,
                          height: 300,
                          padding: EdgeInsets.only(bottom: 10),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: <Widget>[
                              Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: <Widget>[
                                  GestureDetector(
                                    onTap: () => _setPic(context),
                                    child: CircleAvatar(
                                      radius: 79,
                                      backgroundColor: Color(0xFFFFFFFFF),
                                      child: CircleAvatar(
                                        radius: 75,
                                        backgroundImage: profilePicture
                                            ? NetworkImage(_imageUrl)
                                            : AssetImage(_imageUrl),
                                      ),
                                    ),
                                  ),
                                // More code...
    
    
    

    What I'm doing wrong? Why my picture isn't getting updated?

    Updated:


    I tried this, so I can save in pictureTemp the picture's bytes, calling to setState to rebuild the widget and put the picture with Image.memory(pictureTemp). But it doesn't seem to work.

      Uint8List pictureTemp;
      io.File profilePic;
      Future getFromCamara() async {
        var pickedFile = await ImagePicker().getImage(source: ImageSource.camera);
        var image = await pickedFile.readAsBytes();
    
        FirebaseStorage.instance
            .ref()
            .child('picture')
            .putFile(io.File(pickedFile.path));
    
        setState(() {
          pictureTemp = image;
        });
    
    child: CircleAvatar(
              radius: 75,
              backgroundImage: profilePicture
                   ? pictureTemp == null
                     ? AssetImage(_imageUrl)
                     : Image.memory(pictureTemp)
                   : AssetImage(_imageUrl),
           ),
    
  • Sharki
    Sharki over 3 years
    Sorry, could you give me an example of how to implement it based on my code? I've updated with what I tried but I'm a little lost. Thanks
  • Sharki
    Sharki over 3 years
    Solved! Instead of using Image.memory() method I just used the type File so in the widget I can use FileImage(file). Thanks for the hint!