1

I'm trying to call a cloud firestore function that has to persist an object only when another function returns the url of the file in Firebase Storage but the async await is not working and the second function is called anyway whereas the first function is not yet completed!!!

      await schoolProfileProvider.uploadSchoolProfileAvatar(data).then( (data) {
          schoolProfileProvider.addSchoolProfile(data);
        });
        print('PROFILE ADDED');

Future<SchoolProfileData> uploadSchoolProfileAvatar(SchoolProfileData data) async {
    List<File> avatars = [];
    data.childrenDetails.forEach((child) {
      avatars.add(File(child.childImage));
    });
    try {
       await _api.uploadFilesToStorage(avatars, 'image', 'png').then((urls) {
        for (var i = 0; i < urls.length; i++) {
          data.childrenDetails[i].childImage = urls[i];
          print('ADD ' + data.childrenDetails[i].childImage);
        }
      });
    } on Exception catch (e) {
      print(e.toString());
    }
    return data;
  }

  T cast<T>(x) => x is T ? x : null;
  Future<List<String>> uploadFilesToStorage(List<File> files, String type, String extension) async {
    final urls = <Future<String>>[];
    files.forEach((file) async {
      StorageReference storageRef = storage.ref().child(file.path);
      final StorageTaskSnapshot downloadUrl =
      (await storageRef
          .putFile(file, StorageMetadata(contentType: type + '/' + extension))
          .onComplete);
       await downloadUrl.ref.getDownloadURL().then((url) {
        urls.add(cast<Future<String>>(url));
        print('URL for file ${file.path} = ${url.toString()}');
      });
    });
    print ('urls returned');
    return Future.wait(urls);
  }

  Future addSchoolProfile(SchoolProfileData data) async{
    var result;
    try {
      result = await _api.addDocument(data.toJson());
    } on Exception catch(e) {
      print (e.toString());
    }
    return result;
  }
4
  • 1
    This question needs to be brought down to a minimum reproducible example, please. Someone who doesn't have your setup cannot reproduce the problem, and where the problem occurs is not clear. Commented Jan 3, 2020 at 4:09
  • In the then of your method call at the top of your example, you call addSchoolProfile but you don't await it. I wonder if you are thinking that the second method runs before the first is complete because your program prints "PROFILE ADDED" before the second method completes. Commented Jan 3, 2020 at 5:25
  • Actually, I want the async function schoolProfileProvider.addSchoolProfile(data) to be executed only when schoolProfileProvider.uploadSchoolProfileAvatar(data) is finished with the list of storage urls returned Commented Jan 3, 2020 at 16:33
  • You are mixing two different ways of dealing with futures. Try async/await on both or chaining with .then(..). When chaining, you need to return second future from inside of the .then(..) block. Commented Jan 5, 2020 at 2:47

1 Answer 1

1

I've managed to make the things work and execute addSchoolProfile only after uploadFilesToStorage is completed by reducing the nested functions and making the await downloadUrl.ref.getDownloadURL() as the last instruction returned in the callee function. Please find the code for who is interested in :

The caller :

  schoolProfileProvider.addSchoolProfileAndUploadAvatar(data);

  Future addSchoolProfileAndUploadAvatar(SchoolProfileData data) async {
    List<File> avatars = [];
    data.childrenDetails.forEach((child) {
      avatars.add(File(child.childImage));
    });
    try {
         for (int i=0;i<avatars.length;i++){
           await _api.uploadFileToStorageAndGetUrl(avatars[i], 'image', 'png').then((url) {
             print('URL for file ${avatars[i].path} = ${url.toString()}');
             data.childrenDetails[i].childImage = url;
             print('ADD ' + data.childrenDetails[i].childImage);
           });
         }
         _api.addDocument(data.toJson()) ; // Add document in Google Firebase after setting the avatar url
    } on Exception catch (e) {
      print(e.toString());
    }
  }

The callee :

Future <String>  uploadFileToStorageAndGetUrl(File file,String type, String extension) async{
    StorageReference storageRef = storage.ref().child(file.path);
    final StorageTaskSnapshot downloadUrl =
    (await storageRef
            .putFile(file, StorageMetadata(contentType: type + '/' + extension))
    .onComplete);
    return await downloadUrl.ref.getDownloadURL(); // return the url of the file in Google Storage
  }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.