我一直在使用Retrofit来处理我的Android应用程序的REST API调用,它一直很好用。但是,我遇到了关于失去连接和请求失败的问题。我的应用程序涉及以编程方式连接到WiFi网络,然后一旦连接,发出API调用进行初始化。但是,有时这些连接速度很慢,我需要一种能够在失败时重新发送这些请求的方法。这是我转向RxJava的地方,因为在Retrofit中不支持这个。我想要做的是一旦连接到新的WiFi网络发出对REST API的ping并且如果存在网络错误,请等待一秒钟并重试ping。这是我的代码:
界面中的函数声明:
@Headers("Content-Type: application/json")
@GET("something")
io.reactivex.Observable<String> ping();
活动中的改造声明
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Data.cloudEndpoint)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
avfsService = retrofit.create(MyClass.class);
尝试在Activity
中执行API调用service.ping()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
Log.d(TAG, "retryWhen");
return Observable.timer(1, TimeUnit.SECONDS);
}
})
.blockingSubscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscibe " + d.toString());
}
@Override
public void onNext(String s) {
Log.d(TAG, "onNext " + s);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError");
e.printStackTrace();
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
launch();
}
});
所以当这里执行的是我在Logcat中看到的输出
onSubscibe null
retryWhen
onComplete
所以onNext永远不会被调用,我不太清楚为什么。我认为每次从Obeservable发出数据时都会调用onNext,我认为通过创建一个Observable并订阅它,将执行API调用,并且Observable将发出响应。这似乎不是这种情况,因为我现在甚至无法重新创建网络错误,并立即调用onComplete。
我在这里使用的是一个blockingSubscribe因为我看到其他人说可以帮助你在io线程上执行并观察主线程,但没有运气。当我使用.subscribe()时,我看到了相同的行为。
我认为我遗漏了一些内容,但不知道我的API调用是否未被执行,或者我是否只是没有正确回复。
非常感谢任何帮助。
答案 0 :(得分:2)
您的困惑可能来自retryWhen
运算符只调用一次的重试逻辑函数这一事实。由于它向您传递了Observable
Throwable
个,因此当您从error
发出新的throwableObservable
时,它会要求您发出重试可观察量。最简单的方法是将flatmap
错误导入重试逻辑 -
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
Log.d(TAG, "retryWhen");
return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Throwable throwable) throws Exception {
Log.d(TAG, "retrying");
return Observable.timer(1, TimeUnit.SECONDS);
}
});
}
})
如果你运行上述内容,你仍然会看到&#34;重试当&#34;叫一次,然后重试&#34;每当有错误时,您会得到onNext
和onComplete
。您可能希望在一段时间后添加代码以放弃,或者至少确保您正确处理订阅,这样它就不会永远运行。
作为旁注,这段代码(以及一般的RxJava)使用lambdas更具可读性。
如果您仍然想要了解retryWhen
,请查看Dan Lew的this article有一个很好的解释。
答案 1 :(得分:0)
请改为尝试:
service.ping()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Observable<Throwable> throwableObservable) throws Exception {
Log.d(TAG, "retryWhen");
return Observable.timer(1, TimeUnit.SECONDS);
}
})
.subscribe(new Subscriber<String>() {
@Override
public void onNext(String s) {
Log.d(TAG, "onNext " + s);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError");
e.printStackTrace();
}
@Override
public void onCompleted() {
Log.d(TAG, "onComplete");
launch();
}
});
答案 2 :(得分:0)
您的问题来自于您使用blockingSubscribe
这一事实。这会阻塞线程,直到observable完成。
由于您在Android线程上告诉它观察,这可能是被阻止的线程,所以除非onNext
已经被onComplete
发送,否则它永远不会有机会发送这些onNext
个调用被叫,这使得它忽略了任何进一步的observeOn
次呼叫。
您的给定代码可能不会死锁,因为onComplete
保留了onError
和onComplete
来电的优先顺序,如果没有明确告知他们保留订单的话。这意味着它允许.X
调用通过,解锁线程。