I am trying to wrap a Firestore method into CompletableEmitter, to be able to return Completable.complete() on success/complete, and Completable.error() on failure. (The Task is a Firestore operation to update a document(1 field in that document) in a collection)
This is the firestore method
I am trying to wrap into a Completable which returns a Task<Void>
. And here is the code without having it wrapped in a Completable:
public static Completable updateDocument(DocumentReference ref, Map<String,Object> fieldsAndValues){
ref.update(fieldsAndValues)
.addOnSuccessListener(aVoid -> {
Timber.d("SUCCESS");
}).addOnCompleteListener(task -> {
Timber.d("COMPLETE");
}).addOnFailureListener(e -> {
Timber.d("ERROR");
});
return Completable.complete(); //just for the sake of returning complete to finish the method...
}
This above code executes as is should.
Here is my attempt to wrap that code :
public static Completable updateDocument(DocumentReference ref, Map<String,Object> fieldsAndValues){
return Completable.create(emitter -> ref.update(fieldsAndValues)
.addOnSuccessListener(aVoid -> emitter.onComplete())
.addOnCompleteListener(task -> emitter.onComplete())
.addOnFailureListener(emitter::onError));
}
While the first executes with success (onSuccess called, document in Firestore updated), the wrapped code never reaches onSuccess from the Task (onSuccess never reached, document never updated in Firestore). But it does not throw any errors, The Task completes but never reaches success.
I do not understand this behavior. Any suggestions? What do I do wrong here?
You don't necessarily have to use the callbacks for a task - I think that the api is restrictive in this sense.
you can make the task blocking and just evaluate it after execution i.e.
public static Completable updateDocument(DocumentReference ref, Map<String,Object> fieldsAndValues){
return Completable.fromCallable(() -> {
final Task<Void> task = ref.update(fieldsAndValues);
Tasks.await(task);
if(task.isSuccessful()) {
return Completable.complete();
} else {
return Completable.error(new IllegalStateException("Task not successful", task.getException()));
}
});
}
As your original problem, try holding a reference to the task in the closure i.e.
public static Completable updateDocument(DocumentReference ref, Map<String, Object> fieldsAndValues) {
return Completable.create(emitter -> {
final Task<Void> task = ref.update(fieldsAndValues)
task.addOnSuccessListener(aVoid -> emitter.onComplete())
.addOnCompleteListener(task -> emitter.onComplete())
.addOnFailureListener(emitter::onError);
});
}
Have you subscribe
d returned completable?
ref.update()
will be never executed unless you subscribe it
updateDocument(...)
.subscribe(...) // <- this
Note: There is also wrong with your first code.
Completable
s should be executed when they are subscribe
d. However in your first code, it is executed when you call updateDocument()
.
For example, if you do Completable c = updateDocument(...)
, it should not update document because you did not subscribe()
yet but your first code it will update document.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With