使用改造和 rxjava 处理空响应 2.x
Handle empty response with retrofit and rxjava 2.x
当使用 rxjava 1.x 时,我曾经 return Observable<Void>
处理来自改造的空响应:
@POST( "login" )
Observable<Void> getToken( @Header( "Authorization" ) String authorization,
@Header( "username" ) String username,
@Header( "password" ) String password );
但是因为 rxjava 2.x 不会用 Void
发出任何东西,有什么好的做法来处理这些空响应吗?
Completable was designed for such cases. It available since RxJava 1.1.1。来自官方文档:
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)?
所以只需更改方法的 return 类型:
@POST("login")
Completable getToken(@Header("Authorization") String authorization,
@Header("username") String username,
@Header("password") String password);
并重写您的订阅者,例如:
apiManager.getToken(auth, name, pass)
...
.subscribe(() -> {
//success
}, exception -> {
//error
});
您尝试使用 Observable<Object>
了吗?
本文来自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);
另一个解决方案是:
@POST("login")
Observable<Response<Void>> getToken(@Header("Authorization") String authorization,
@Header("username") String username,
@Header("password") String password);
更新:
但我宁愿使用 Completable
所以接受的答案只是部分正确。 Completable
在某些情况下会起作用,其中预期只有一次发射,但是,Completable
只会发射一次,之后不会发射。它类似于 Single
(除了我们忽略发出的值)。另一方面,Observable
可以发出 多次 次。因此,如果源 observable 将发出多次,至少在 RxJava2 中,答案是发出类似 Observable<Irrelevant>
的东西(其中 Irrelevant
是静态的 enum/class),或者更好的是 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());
});
}
}
当使用 rxjava 1.x 时,我曾经 return Observable<Void>
处理来自改造的空响应:
@POST( "login" )
Observable<Void> getToken( @Header( "Authorization" ) String authorization,
@Header( "username" ) String username,
@Header( "password" ) String password );
但是因为 rxjava 2.x 不会用 Void
发出任何东西,有什么好的做法来处理这些空响应吗?
Completable was designed for such cases. It available since RxJava 1.1.1。来自官方文档:
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)?
所以只需更改方法的 return 类型:
@POST("login")
Completable getToken(@Header("Authorization") String authorization,
@Header("username") String username,
@Header("password") String password);
并重写您的订阅者,例如:
apiManager.getToken(auth, name, pass)
...
.subscribe(() -> {
//success
}, exception -> {
//error
});
您尝试使用 Observable<Object>
了吗?
本文来自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);
另一个解决方案是:
@POST("login")
Observable<Response<Void>> getToken(@Header("Authorization") String authorization,
@Header("username") String username,
@Header("password") String password);
更新: 但我宁愿使用 Completable
所以接受的答案只是部分正确。 Completable
在某些情况下会起作用,其中预期只有一次发射,但是,Completable
只会发射一次,之后不会发射。它类似于 Single
(除了我们忽略发出的值)。另一方面,Observable
可以发出 多次 次。因此,如果源 observable 将发出多次,至少在 RxJava2 中,答案是发出类似 Observable<Irrelevant>
的东西(其中 Irrelevant
是静态的 enum/class),或者更好的是 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());
});
}
}