0

I am working on a simple app that should work like uber, I want each driver to upload the image of his/her car while setting up his/her profile. I have successfully picked the two images and was able to save them to the firebaseStorage, I want to retrieve the link to the downloaded car Image and save it to the driver database reference along with his profile picture and other information but I am unable to do that. I create a method that returns a String so that I can use the String returned by that method as the link to the car Image but it's showing null in my database.

The method that should return the link to the downloaded car image:

private Uri profileImageUri, carImageUri;
private StorageReference storageProfilePicsRef, storageCarImageRef;
private StorageTask uploadProfileTask, uploadCarImageTask;
 private String myProfileImaeUri = "", myCarImageUri = "";

private String uploadCarImage() {
        if (carImageUri != null) {
            final StorageReference storageReference = storageCarImageRef.child(mAuth.getCurrentUser().getUid() + ".jpg");
            uploadCarImageTask = storageReference.putFile(carImageUri);

            uploadCarImageTask.continueWithTask(new Continuation() {
                @Override
                public Object then(@NonNull Task task) throws Exception {
                    if (!task.isSuccessful()) {
                        throw task.getException();
                    }
                    return storageReference.getDownloadUrl();
                }
            }).addOnCompleteListener(new OnCompleteListener<Uri>() {
                @Override
                public void onComplete(@NonNull Task<Uri> task) {
                    if (task.isSuccessful()) {
                        Uri downloadCarUri = task.getResult();

                        myCarImageUri = downloadCarUri.toString();
                    }
                }
            });
        } else {
            Toast.makeText(SettingsActivity.this, "Car Image Not Selected", Toast.LENGTH_SHORT).show();
        }
        return myCarImageUri;
    }

This is the method that upload both the profile image and other information of the driver:

private void uploadProfilePicture() {

        String carImageUriFromTheMethod = uploadCarImage();//I was trying to assigned the method that returns the carImage link as a String to this String type variable so that I can use it

        final ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setTitle("Updating Profile");
        progressDialog.setMessage("Please wait while we are updating your account information");
        progressDialog.setCanceledOnTouchOutside(false);
        progressDialog.show();
        if (profileImageUri != null) {

            final StorageReference fileRef = storageProfilePicsRef.child(mAuth.getCurrentUser().getUid() + ".jpg");
            uploadProfileTask = fileRef.putFile(profileImageUri);

            uploadProfileTask.continueWithTask(new Continuation() {
                @Override
                public Object then(@NonNull Task task) throws Exception {
                    if (!task.isSuccessful()) {
                        throw task.getException();
                    }
                    return fileRef.getDownloadUrl();
                }
            }).addOnCompleteListener(new OnCompleteListener<Uri>() {
                @Override
                public void onComplete(@NonNull Task<Uri> task) {
                    if (task.isSuccessful()) {
                        Uri downloadUri = task.getResult();
                        myProfileImaeUri = downloadUri.toString();

                        int selectedID = radioGroup.getCheckedRadioButtonId();
                        male = (RadioButton)findViewById(selectedID);
                        female = (RadioButton) findViewById(selectedID);
                        if (male.isChecked()){
                            selectedGender = male.getText().toString();
                        }else if (female.isChecked()){
                            selectedGender = female.getText().toString();
                        }else {
                            selectedGender = "Not specify";
                        }

                        HashMap<String, Object> hashMap = new HashMap<>();
                        hashMap.put("ProfileImage", myProfileImaeUri);
                        hashMap.put("name", name.getText().toString());
                        hashMap.put("city", city.getText().toString());
                        hashMap.put("age", age.getText().toString());
                        hashMap.put("maritalStatus", maritalStatus.getText().toString());
                        hashMap.put("phoneNumber", phoneNumber.getText().toString());
                        hashMap.put("country", country.getText().toString());
                        hashMap.put("address", address.getText().toString());
                        hashMap.put("gender", selectedGender);
                        hashMap.put("carName",carName.getText().toString());
                            hashMap.put("carColour", carColor.getText().toString());
                            hashMap.put("carPlateNumber", carPlateNumber.getText().toString());
                            hashMap.put("carImage", carImageUriFromTheMethod);//I now call the string here
 }
                        databaseReference.child(mAuth.getCurrentUser().getUid()).updateChildren(hashMap);

                        progressDialog.dismiss();
                        if (getType.equalsIgnoreCase("Driver")) {

                            startActivity(new Intent(SettingsActivity.this, DriversMapsActivity.class));
                            Toast.makeText(SettingsActivity.this, "Profile Information Updated Successfully", Toast.LENGTH_SHORT).show();
                            finish();
                        } else {
                            startActivity(new Intent(SettingsActivity.this, CustomerMapsActivity.class));
                            Toast.makeText(SettingsActivity.this, "Profile Information Updated Successfully", Toast.LENGTH_SHORT).show();
                            finish();
                        }
                    } else {
                        Toast.makeText(SettingsActivity.this, "Error Occured", Toast.LENGTH_SHORT).show();
                        progressDialog.dismiss();
                    }
                }
            });
        } else {
            Toast.makeText(SettingsActivity.this, "Profile Image Not Selected", Toast.LENGTH_SHORT).show();
        }

    }

Here is my database which shows that the carImage is null, but there is a car Image in the firebaseStorage:

"Driver": {
  "2oKrtyUa3FX1wyHAhplsxbVaPZU2": {
    "ProfileImage": "https://firebasestorage.googleapis.com/v0/b/ride-booking-app-e8a95.appspot.com/o/Profile%20Images%2F2oKrtyUa3FX1wyHAhplsxbVaPZU2.jpg?alt=media&token=442b14b3-ffb8-4356-b0c0-4c77021fe391",
    "address": "Ikot Obong",
    "age": "28",
    "carColour": "black",
    "carImage": "",//this is where the link supposed to appear as it's seen in the profile image
    "carName": "Range Rover sport",
    "carPlateNumber": "aa377-ktm",
    "city": "Ikot Abasi",
    "country": "Nigeria",
    "gender": "Male",
    "maritalStatus": "single",
    "name": "Captain Elijah",
    "phoneNumber": "08168989070"
  }
}

Thanks for help

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Ukeme Elijah
  • 157
  • 3
  • 13
  • Here are you getting null? – Alex Mamo May 27 '22 at 10:52
  • Am getting null from that last data that I wanted to add into the map, that place that I wrote hasMap.put("carImage",carImageUriFromTheMethod), I was thinking that it will return the link to the image that I stored in that private String uploadCarImage() method. And if you check that my database, you will see that the place for carImage is empty, I hoped that you understands my question @AlexMamo – Ukeme Elijah May 27 '22 at 14:04

1 Answers1

0

All the operations you are doing (uploading the image, getting its download URL, and writing to the database) are asynchronous, which your code ignores.

If you log the myCarImageUri in uploadCarImage right before you return it, you'll see it's null, which is the case because your onComplete for the upload hasn't run yet (another log would show that too).


The correct way to handle the uploads is as you already do for the myProfileImaeUri in your uploadProfilePicture method: nesting the callbacks, so that they execute in the correct order. You'll need to do the same for the car image.

To learn more about this problem, I recommend checking out some of the top answers on the asynchronous behavior of getDownloadUrl(), such as my answers to:

I'd also recommend reading Doug's excellent series of blog posts on becoming a Firebase task master.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Please Sir can you explain a little bit more on what to do because I have checked back my code and the same approach I used in getting the image link in the uploadProfilePicture method is also the approach in the uploadCarImage method. I don't want to save the data into the database in that method as I did in the uploadProfilePicture method. All what I need in that method is to get the link to the dwonloaded image and store it in a String so that I can use it in the uploadProfilePicture method in the hasMap that requires carImage as a String parameter. That's the issue that I want to overcome – Ukeme Elijah May 27 '22 at 15:02
  • The code to write to the database is *inside* the `onComplete` of your profile pic task, but it is *not* inside the `onComplete` of the car picture task. To make sure the write to the database has the download URLs for both the car picture and the profile picture, it'll need to be inside the `onComplete` handlers of both of these, so you'll need to nest them. – Frank van Puffelen May 27 '22 at 15:48
  • Please Sorry for the too much question, you mean I should also store the link of the image in a hashmap and send it different to the database as I did in the uploadProfilePicture method? – Ukeme Elijah May 27 '22 at 16:35