1

I am trying to upload a custom object to Firebase Firestore, but the Firestore object should contain a download image url. The idea I have to do this is to upload the image first wait for that to complete, get a reference to the download url, update my custom class, then upload this to Firestore. I would then want to notify my view when this last upload(upload to Firestore) is completed. I was thinking of doing this by returning a task. Here is what I have for upload image:

ref.putFile(file).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            ref.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                @Override
                public void onSuccess(Uri uri) {
                    //use uri to update object and then upload to firestore

                       mObject.setImageUri(uri)
                       uploadToFirestore(myObject);
                    }
                    Log.d(TAG, "onSuccess: uri= "+ uri.toString());
                }
            });
        }
    });`

I am not sure how to return the final task of Firstore upload as it is done within the task of image upload. My goal is to listen for when the uploadToFireStore() is completed and then inform my view. Any suggestions would be appreciated. Thanks!

Edit: I have structure like so- View has gets info from user passes it to viewmodel as a custom object. View model then calls db to perform upload. my idea is to return a task from db to viewmodel which will return said task to view. View checks for completion and then stops loader. Is this a good way to think about this?

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
user642206
  • 149
  • 1
  • 8

2 Answers2

1

My working example.

public class SomeClass {
    private String downloadUrl;
    private final FirebaseStorage storage = FirebaseStorage.getInstance();
    private int count = 0;

    public interface Callback {
        void callingBack();
        void getReady();
    }

    public int getCount() {
        return count;
    }

    private Callback callback;

    public void registerCallBack(Callback callback) {
        this.callback = callback;
    }


    public String getImageUri () {
        return downloadUrl;
    }

    public void uploadImage (String srcPath, String fileName, Context context, int size) {
        StorageReference storageRef = storage.getReference();
        StorageReference imageRef = storageRef.child(fileName);
        try {
            InputStream inputStream = new FileInputStream(new File(srcPath));
            imageRef.putStream(inputStream)
                    .continueWithTask(task -> imageRef.getDownloadUrl())
                    .addOnCompleteListener(task -> {
                        downloadUrl = task.getResult().toString();
                        callback.callingBack();
                        this.count++;
                        if (this.count == size) {
                            callback.getReady();
                            this.count = 0;
                        }
                    });
        } catch (Exception e) {
            Toast.makeText(context, "Connection error", Toast.LENGTH_LONG).show();
        }
    }    
}

Activity Code

    public void someMehtod() {

            String fileName;
            String filePath;
            int size = YOUR_SIZE;
            String[] imgUrlList = new String[size];
            for (int i = 0; i < size; i++) {
                fileName = "img_" + i + ".jpg"; // set target file name
                filePath = "/storage/emulated/0/Download/images_" + i + ".jpg"; // for example (u need get your real source file paths)
                getImageUri.registerCallBack(new GetImageUri.Callback() {
                    @Override
                    public void callingBack() {
                        imgUrlList [getImageUri.getCount()] = getImageUri.getImageUri();
                        }
                    }
    
                    @Override
                    public void getReady() {
                        // here u can use your URLs
                        for (int k = 0; k < size; k ++) {
                            Log.d(TAG, "getReady: " + imgUrlList [k]);    
                    }
                });
                getImageUri.uploadImage(filePath, fileName, this.getContext(), imgListCount);
            }
        }
Din
  • 11
  • 2
0

I figured out how to solve the issue. Using callbacks. Create an interface like so

public interface Callback {
  void result(Result result);
  void url(Uri downloadUrl);
}

Note: result is an enum class with two values FAILED and SUCCESS Then in your view call the view model like so

ViewModel.saveoBJECT(mObject, new Callback() {
        @Override
        public void result(Result result) {
            switch (result){
                case SUCCESS:
                    mProgressbar.setVisibility(View.GONE);
                    break;
                case FAILED:
                    Log.v(TAG, "Failed");
                    Toast.makeText(getApplicationContext(), "OOPS ERROR!", Toast.LENGTH_LONG).show();
                    break;
            }
        }

        @Override
        public void url(Uri downloadUrl) { }
    });

and in your db do do something like this

  uploadImage(Uri.parse(imageString), prepend, new Callback() {
            @Override
            public void result(Result result) {}

            @Override
            public void uri(Uri downloadUrl) {
                saveObjectInDB(downloadUrl, new Callback() {
                    @Override
                    public void result(Result result) {
                        callback.result(result);
                    }

                    @Override
                    public void url(Uri downloadUrl) { }
                });
            }
        });

in the upload image function

 ref.putFile(file).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
            ref.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
                @Override
                public void onSuccess(Uri uri) {
                    callback.journey(uri);
                    Log.d(TAG, "onSuccess: uri= "+ uri.toString());
                }
            });
        }
    });

and in saveObjectInDB function you do this

 db.collection(DATABASE).add(O)
        .addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
            @Override
            public void onSuccess(DocumentReference documentReference) {
                Log.w(TAG, "Document upload complete");
                callback.result(Result.SUCCESS);
            }
        })
        .addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "Error adding uploading document", e);
                callback.result(Result.FAILED);
            }
        });
user642206
  • 149
  • 1
  • 8