Search code examples
javaandroidrx-javafirebase-storage

How do I wrap a Firebase OnCompleteListener with a RxJava Single<>?


I'm using Firebase to upload an image. I'm using Firebase's .onCompleteListener() to get the URL of the uploaded image in the callback.

I'm trying to incoorporate this into my Repository class with a Single<>, but I'm unsure how to do it.

Could someone please help me figure out what I'm doing incorrectly?

public Single<String> uploadImage(String path) {
        Uri uri = Uri.fromFile(new File(path));
        String fileName = createNewFileName(uri);
        StorageReference ref = firebaseStorage.getReference().child(fileName);

        return Single.fromCallable(() -> {
            UploadTask uploadTask = ref.putFile(uri);
            uploadTask.continueWithTask(task -> {
                if (!task.isSuccessful()) {
                    throw task.getException();
                }
                return ref.getDownloadUrl();
            }).addOnCompleteListener(task -> {
                if (task.isSuccessful()) {
                    Uri downloadUri = task.getResult();
                    String url = downloadUri.toString();
                    
                    //String to use in Single<>
                } else {
                    //Handle Error
                }
            });
        });

    }

enter image description here

To use in my ViewModel

uploadImage(path)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(url -> {
                    
        }, err -> {
                    
        });

Solution

  • You need Single.create:

    Provides an API (via a cold Single) that bridges the reactive world with the callback-style world.

    return Single.<String>create(emitter -> {
                UploadTask uploadTask = ref.putFile(uri);
                uploadTask.continueWithTask(task -> {
                    if (!task.isSuccessful()) {
                        throw task.getException();
                    }
                    return ref.getDownloadUrl();
                }).addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        Uri downloadUri = task.getResult();
                        String url = downloadUri.toString();
                        
                        emitter.onSuccess(url);
                    } else {
                        emitter.onError(task.getException());
                    }
                });
            });