我想调用API api1
,并将API返回的输出传递给第二个API api2
。第一个API是获取请求,第二个API是POST
请求。因此,api1
返回Single<String>
,而api2
返回Completable
。
函数看起来像这样:
// api1
public Single<String> getToken() {
...
}
// api2
public Completable saveTokenToBackend(String token, String userId) {
...
}
我想将这两个操作链接在一起。订户仅想知道获取令牌并保存令牌的过程是否成功。因此,最后一个操作链的返回类型应为Completable
。但是,当我这样做时,API调用api2
就会停止。根据日志,只有api1
成功工作。
Single<Completable> r1 = getToken().map(t -> saveTokenToBackend(t, userId));
Completable r2 = Completable.fromSingle(r1);
我在这里的更广泛的问题是,我如何将响应从单一链接到完成?
第二个问题是为什么上面的代码不起作用?
:: EDIT ::
根据评论中的建议,我尝试了:
public Completable getAndSaveToken() {
getToken().flatMapCompletable(t -> saveTokenToBackend(t, "dummyuser");
}
我正在使用我的应用代码:
getAndSaveToken()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> {
Log.v(TAG, "call success");
}, error -> {
Log.e(TAG, "Error", error);
});
结果:java.io.IOException: Must not be called on the main application thread
答案 0 :(得分:2)
您有2个不同的问题,组成和安排。上下文:getToken
返回单个,而saveToken(token)
返回一个完成。
组成:要组成一个和一个可完成对象,您已经注意到,可以使用flatMap运算符,这将返回一个新的可完成对象,该对象首先获取令牌,然后将其保存(可能是,则需要在保存令牌之前对其进行修改;)
getToken().flatMapCompletable(n -> saveToken(n)) // returns a completable
如果您希望将其保留为单个,则可以将其映射回第一个实例:
getToken().flatMap(n -> saveToken(n).toSingleDefault(n)) // returns a single
计划:在android中,您不得在主线程中启动请求。为了避免这种情况,您可以使用subscribeOn
运算符,看起来您已经注意到了
getToken().subscribeOn(io()).doOnNext(n -> {/*this should be evaluated in io thread*/})
getToken().subscribeOn(io()).observeOn(mainThread()).doOnNext(n -> {/*this on mainThread*/})
如果仍然出现错误,则说明observeOn
或subscribeOn
已在某处重新配置。需要更多代码以确保。但是无论如何,您都可以断言两次请求都在io线程中应用了两次运算符来执行:
getToken().subscribeOn(io).flatMapCompletable(token -> saveToken(token).subscribeOn(io()))
如果正在使用改造,另一种选择是使用RxJava2CallAdapterFactory
工厂而不是默认工厂来应用createWithScheduler(io())
。这将断言所有请求都是在io()中创建的,因此您可以合并并准备数据,最后应用observeOn(mainThread())
来更新UI。