Retrofit + RxJava Android onNext从未调用但是onComplete是

时间:2018-03-30 01:20:38

标签: android rest retrofit rx-java2

我一直在使用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调用是否未被执行,或者我是否只是没有正确回复。

非常感谢任何帮助。

3 个答案:

答案 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;每当有错误时,您会得到onNextonComplete。您可能希望在一段时间后添加代码以放弃,或者至少确保您正确处理订阅,这样它就不会永远运行。

作为旁注,这段代码(以及一般的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保留了onErroronComplete来电的优先顺序,如果没有明确告知他们保留订单的话。这意味着它允许.X调用通过,解锁线程。