Masquitos
Masquitos

Reputation: 536

Repeat Retrofit2 request using repeatWhen RxJava2

I'm working with rxjava2. My problem is that sometimes server sends me nothing (response body is null, and so on List size = 0), so in that case I'd like to repeat request after 5 sec. I have an Retrofit2 request:

  @GET("/ics/api/{bidId}/calltracking/reports/widgets")
    Single<List<CallTrackingWidget>> getWidgets(@Path("bidId") int bidId);

Use it like so:

RetrofitFactory.getRetrofitService().getWidgets(mDataManager.getBidId())
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .doOnSubscribe(widgets -> getView().showLoading())
                .doOnSuccess(widgets -> getView().hideLoading())
                .repeatWhen(widgets -> widgets.flatMap(size -> {
                    if ((int) size == 0) {
                        return Flowable.just("asd").delay(5, TimeUnit.SECONDS);
                    } else {
                        return widgets;
                    }
                }))
                .subscribe(widgets -> {
                    mDataManager.getProduct().getCallTrackingData().setWidgets(widgets);
                    getView().initWidgets(mDataManager.getProduct().getCallTrackingData().getWidgetNames());
                }, throwable -> {
                    handleError(throwable, R.string.error_internet);
                })

But my code a have an exeption:

android.view.ViewRootImpl$CalledFromWrongThreadException: 
Only the original thread that created a view hierarchy can touch its views.

Help me please to repeat request after 5 sec, when List size is 0.

Upvotes: 0

Views: 774

Answers (2)

wenhelinlu
wenhelinlu

Reputation: 1

Because you don't deal with the view on main thread, you can write like this:

RetrofitFactory.getRetrofitService().getWidgets(mDataManager.getBidId())
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .doOnSubscribe(widgets -> getView().showLoading())
    .subscribeOn(AndroidSchedulers.mainThread())
    .repeatWhen(widgets - > widgets.flatMap(size - > {
        if ((int) size == 0) {
            return Flowable.just("asd").delay(5, TimeUnit.SECONDS);
        } else {
            return widgets;
        }
    }))
    .subscribe(widgets - > {
        getView().hideLoading(); // Hide loading view
        mDataManager.getProduct().getCallTrackingData().setWidgets(widgets);
        getView().initWidgets(mDataManager.getProduct().getCallTrackingData().getWidgetNames());
    }, throwable - > {
        getView().hideLoading(); // Hide loading view
        handleError(throwable, R.string.error_internet);
    })

Upvotes: 0

Abhishek Jain
Abhishek Jain

Reputation: 3702

I think your problem lies in these two lines:

.doOnSubscribe(widgets -> getView().showLoading())
.doOnSuccess(widgets -> getView().hideLoading())

These two actions will execute off the Main thread. And as the exception implies, you can only touch Android views from the Main thread.

Try moving this view manipulation somewhere else. Like this:

getView().showLoading(); // Show loading view
RetrofitFactory.getRetrofitService().getWidgets(mDataManager.getBidId())
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .repeatWhen(widgets - > widgets.flatMap(size - > {
        if ((int) size == 0) {
            return Flowable.just("asd").delay(5, TimeUnit.SECONDS);
        } else {
            return widgets;
        }
    }))
    .subscribe(widgets - > {
        getView().hideLoading(); // Hide loading view
        mDataManager.getProduct().getCallTrackingData().setWidgets(widgets);
        getView().initWidgets(mDataManager.getProduct().getCallTrackingData().getWidgetNames());
    }, throwable - > {
        getView().hideLoading(); // Hide loading view
        handleError(throwable, R.string.error_internet);
    })

Upvotes: 1

Related Questions