Not able to store download URLs inside Firebase Firestore

Viewed 53

I am trying to store images into Firebase Storage and then download the URI of those images from Firebase storage and then again upload those URI into the firebase firestore using a foreach loop . Images are successfully uploading into the firebase storage but Uri of only last image is going into firestore first three are failing. I created AN ARRAY LIST OF BITMAPS and then used foreach loop on it.

My Code

    private void UploadingImage() {

        if (bitmap != null && bitmap2 != null && bitmap3 != null && bitmap4 != null) {

            StorageTask arrayUpload;
            fuser = FirebaseAuth.getInstance().getCurrentUser();
            ProductName = Objects.requireNonNull(Product_Name_EditText.getText()).toString();
            CityName = Objects.requireNonNull(CityNameEditText.getText()).toString();

            // Bitmap[] bitmaps=new Bitmap[3];
            ArrayList<Bitmap> bitmapArrayList = new ArrayList<>();
            bitmapArrayList.add(bitmap);
            bitmapArrayList.add(bitmap2);
            bitmapArrayList.add(bitmap3);
            bitmapArrayList.add(bitmap4);

            Bitmap bitresized;

            for (Bitmap bitUpload : bitmapArrayList)
            {
                bitresized = Bitmap.createScaledBitmap(bitUpload, 800, 800, true);
                ByteArrayOutputStream baosArray = new ByteArrayOutputStream();
                bitresized.compress(Bitmap.CompressFormat.JPEG, 70, baosArray);
                byte[] uploadbaosarray = baosArray.toByteArray();
                i = i + 1;
                fileReference = storageReference.child(ProductName).child(i + ProductName + ".jpg");

                arrayUpload = fileReference.putBytes(uploadbaosarray);

                arrayUpload.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
                    @Override
                    public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
                        if (!task.isSuccessful()) {
                            throw task.getException();
                        } else if (task.isSuccessful()) {
                            Toast.makeText(Upload_New_Product.this, "Uploaded Successfully", Toast.LENGTH_SHORT).show();
                            //mProgressBar.setVisibility(View.INVISIBLE);
                        }

                        return fileReference.getDownloadUrl();
                    }
                }).addOnCompleteListener(new OnCompleteListener<Uri>() {
                    @Override
                    public void onComplete(@NonNull Task<Uri> task) {
                        if (task.isSuccessful()) {
                            Uri downloadUri = task.getResult();
                            assert downloadUri != null;
                            String mUri = downloadUri.toString();

                            ProductName = Product_Name_EditText.getText().toString();
                            ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document(ProductName);
                            HashMap<String, Object> map = new HashMap<>();
                            map.put("imageURL" + i, mUri);
                            //reference.updateChildren(map);
                            ProductRef.set(map, SetOptions.merge());

                        } else {
                            Toast.makeText(Upload_New_Product.this, "Failed!", Toast.LENGTH_SHORT).show();
                        }
                    }
                }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Toast.makeText(Upload_New_Product.this, e.getMessage(), Toast.LENGTH_SHORT).show();
                        //pd.dismiss();
                    }
                });

            }
        }
}
1 Answers

Since uploading (and getting the download URL) are asynchronous operations, the for loop completes almost immediately, and all uploads are happening in parallel after that. This means that by the time your map.put("imageURL" + i, mUri) runs, the i variable is going to be its final value.

To make the code work, you need to capture the variable of i for each iteration over the loop. A simple way to do that, is to move the code that uploads the image and stores its URL into a separate function, and pass the value of i into that function call.

Something like:

public void uploadFileAtIndex(int i) {
    fileReference = storageReference.child(ProductName).child(i + ProductName + ".jpg");

    arrayUpload = fileReference.putBytes(uploadbaosarray);

    arrayUpload.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
        @Override
        public Task<Uri> then(@NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
            if (!task.isSuccessful()) {
                throw task.getException();
            } else if (task.isSuccessful()) {
                Toast.makeText(Upload_New_Product.this, "Uploaded Successfully", Toast.LENGTH_SHORT).show();
            }

            return fileReference.getDownloadUrl();
        }
    }).addOnCompleteListener(new OnCompleteListener<Uri>() {
        @Override
        public void onComplete(@NonNull Task<Uri> task) {
            if (task.isSuccessful()) {
                Uri downloadUri = task.getResult();
                assert downloadUri != null;
                String mUri = downloadUri.toString();

                ProductName = Product_Name_EditText.getText().toString();
                ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document(ProductName);
                HashMap<String, Object> map = new HashMap<>();
                map.put("imageURL" + i, mUri);
                ProductRef.set(map, SetOptions.merge());
            } else {
                Toast.makeText(Upload_New_Product.this, "Failed!", Toast.LENGTH_SHORT).show();
            }
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Toast.makeText(Upload_New_Product.this, e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

And then use it in the loop with:

for (Bitmap bitUpload : bitmapArrayList) {
    ...
    i = i + 1;
    uploadFileAtIndex(i);
}

You might need to pass more of your variable to uploadFileAtIndex than I've done here, but its passing i that solves the problem you have right now.

Related