Handle empty response with retrofit and rxjava 2.x
Asked Answered
C

4

24

When using rxjava 1.x i used to return Observable<Void> to handle empty response from retrofit:

@POST( "login" )
Observable<Void> getToken( @Header( "Authorization" ) String authorization,
                                       @Header( "username" ) String username,
                                       @Header( "password" ) String password );

But since rxjava 2.x won't emit anything with Void is there any good practice to handle those empty responses?

Coz answered 9/1, 2017 at 23:36 Comment(0)
P
46

Completable was designed for such cases. It available since RxJava 1.1.1. From the official docs:

Represents a deferred computation without any value but only indication for completion or exception. The class follows a similar event pattern as Reactive-Streams: onSubscribe (onError|onComplete)?

So just change your method's return type:

@POST("login")
Completable getToken(@Header("Authorization") String authorization,
                     @Header("username")      String username,
                     @Header("password")      String password);

And rewrite your subscriber, e.g.:

apiManager.getToken(auth, name, pass)
    ...
    .subscribe(() -> {
        //success
    }, exception -> {
        //error
    });
Paleontology answered 10/1, 2017 at 8:5 Comment(2)
This solution won't work if the response can be either empty for success or error with bodyPhenformin
Good solution for "fire and forget" requests. Thanks!Baldachin
J
7

Another solution is:

@POST("login")
Observable<Response<Void>> getToken(@Header("Authorization") String authorization,
                                    @Header("username") String username,
                                    @Header("password") String password);

Update: But I would rather use Completable

Josiahjosias answered 8/12, 2017 at 10:46 Comment(0)
H
0

So the accepted answer is only partially correct. Completable will work in some cases where one and only one emission is expected, however, Completable will only emit once, and will not emit after that. It is similar to Single (except we ignore the value being emitted). Observable, on the other hand, can emit multiple times. So if the source observable will emit multiple times, the answer, at least in RxJava2, is to emit something like Observable<Irrelevant> (where Irrelevant is a static enum/class), or better yet Observable<Kotlin.Unit>.

public class Source {
    private PublishSubject<Kotlin.Unit> heartbeatOperation;
...
    void getHeartbeats() {
         while(getHeartbeatFromSource() != null) {
             hearbeatOperation.accept(Unit.INSTANCE);
         }  
    }

    public Observable<Unit> heartbeats() {
         return hearbeatOperation.hide();
    }
...
}


public class SourceConsumer {
   @Inject Source source;
...
    void printHearbeats() {
         source.heartbeats()
         .subscribe(unused -> {
             System.out.println("Heartbeat received at " + DateTime.now());
         });
    }
}
Harbourage answered 23/6, 2020 at 0:6 Comment(0)
M
-1

Did you try using Observable<Object> ?

This is from the official documentation of RxJava 2:

enum Irrelevant { INSTANCE; }

Observable<Object> source = Observable.create((ObservableEmitter<Object> emitter) -> {
   System.out.println("Side-effect 1");
   emitter.onNext(Irrelevant.INSTANCE);

   System.out.println("Side-effect 2");
   emitter.onNext(Irrelevant.INSTANCE);

   System.out.println("Side-effect 3");
   emitter.onNext(Irrelevant.INSTANCE);
});

source.subscribe(e -> { /* Ignored. */ }, Throwable::printStackTrace);
Metalliferous answered 10/1, 2017 at 8:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.