我正在尝试为Retrofit2 / RxJava调用实现分页。
我正在使用以下版本:-
retrofit2Version = "2.4.0"
rxAndroidVersion = "2.0.2"
rxJavaVersion = "2.1.16"
okhttp3Version = "3.10.0"
我的Retrofit API调用返回
Single<Response<ModelObject>>
目前,我正在一次调用中检索所有数据,然后将数据保留在本地数据库中。
尽管我要检索两种类型的数据。
我现有的RxJava流程是这样的:-
initialCompletable()
.doOnSubscribe(compositeDisposable::add)
.andThen(Completable.defer(Database::delete))
.andThen(Single.defer(() -> Network.getData(TYPE_ONE)))
.doOnSuccess(persistData())
.ignoreElement()
.andThen(Single.defer(() -> Network.getData(TYPE_THREE)))
.doOnSuccess(persistData())
.ignoreElement()
.retryWhen(errors -> errors.flatMap(e -> constructRetryHandler(counter)))
.doOnComplete(onComplete)
.doOnError(onError)
.doFinally(Finally())
.blockingAwait();
我需要在上述内容中加入分页,例如:-
initialCompletable()
.doOnSubscribe(compositeDisposable::add)
.andThen(Completable.defer(Database::delete))
//Repeat these two steps until no data is returned, incrementing offset by limit each time.
.andThen(Single.defer(() -> Network.getData(TYPE_ONE, offset, limit)))
.doOnSuccess(persistData())
.ignoreElement()
//Repeat these two steps until no data is returned, incrementing offset by limit each time.
.andThen(Single.defer(() -> Network.getData(TYPE_THREE, offset, limit)))
.doOnSuccess(persistData())
.ignoreElement()
.retryWhen(errors -> errors.flatMap(e -> constructRetryHandler(counter)))
.doOnComplete(onComplete)
.doOnError(onError)
.doFinally(Finally())
.blockingAwait();
我尝试了以下方法,但是我必须使用Observables而不是Singles。 同样,即使有更多数据要检索,这种方法也只会返回两页
initialCompletable().doOnSubscribe(compositeDisposable::add)
.andThen(Completable.defer(Database::delete))
.andThen(Observable.defer(() -> getPageAndNext(offset, limit)))
.concatMap(new Function<Response<ModelObject>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(final Response<ModelObject> response) throws Exception {
return Observable.just(response);
}
})
.doOnComplete(onComplete)
.doOnError(onError)
.doFinally(Finally())
.blockingSubscribe();
private ObservableSource<Response<ModelObject>> getPageAndNext(@NonNull final AtomicInteger offset, @NonNull final AtomicInteger limit) {
return Network.getData(TYPE_ONE, offset.get(), limit.get())
.toObservable().concatMap(new Function<Response<ModelObject>, ObservableSource<Response<ModelObject>>>() {
@Override
public ObservableSource<Response<ModelObject>> apply(final Response<ModelObject> response) {
if (isResponseErrorFree(response)) {
if (isDataRetrieved(response)) {
persist(response.body());
return Network.getData(TYPE_ONE, offset.addAndGet(limit.get()), limit.get()).toObservable();
} else {
return Observable.empty();
}
} else {
throw new RuntimeException("Retrieve Failed");
}
}
});
}
我可以使用RxJava repeatWhen()重复流的一部分吗?
我必须将我的单身人士转换为可观察者吗?
更新
我修复了递归问题,仅返回了两个“页面”,并获得了有效的解决方案。
我还是不喜欢在Single和Observables之间切换,我不确定它是否“重要”
initialCompletable().doOnSubscribe(compositeDisposable::add)
.andThen(Completable.defer(Database::delete))
.andThen(Observable.defer(() -> getPageAndNextTypeOne(offset, limit)))
.ignoreElements()
.andThen(Completable.create(completableEmitter -> {
offset.set(0);
completableEmitter.onComplete();
}))
.andThen(Observable.defer(() -> getPageAndNextTypeThree(offset, limit)))
.ignoreElements()
.retryWhen(errors -> errors.flatMap(e -> constructRetryHandler(retryCounter)))
.doOnComplete(onComplete)
.doOnError(onError)
.doFinally(Finally())
.blockingAwait();
}
/**
* @param offset
* @param limit
* @return
*/
private ObservableSource<Response<ModelObject>> getPageAndNextTypeOne(@NonNull final AtomicInteger offset, @NonNull final AtomicInteger limit) {
return Network.getTypeOne(offset.get(), limit.get())
.toObservable().concatMap((Function<Response<ModelObject>, ObservableSource<Response<ModelObject>>>) response -> {
if (isResponseErrorFree(response)) {
if (isInboxArticlesRetrieved(response)) {
persistTypeOne(response.body());
offset.addAndGet(limit.get());
return Observable.just(response).concatWith(getPageAndNextTypeOne(offset, limit));
} else {
return Observable.empty();
}
} else {
throw new RuntimeException("Failed");
}
});
}
/**
* @param offset
* @param limit
* @return
*/
private ObservableSource<Response<ModelObject>> getPageAndNextTypeThree(@NonNull final AtomicInteger offset, @NonNull final AtomicInteger limit) {
return Network.getTypeThree(offset.get(), limit.get())
.toObservable().concatMap((Function<Response<ModelObject>, ObservableSource<Response<ModelObject>>>) response -> {
if (isResponseErrorFree(response)) {
if (isReadingListRetrieved(response)) {
persistTypeThree(response.body());
offset.addAndGet(limit.get());
return Observable.just(response).concatWith(getPageAndNextTypeThree(offset, limit));
} else {
return Observable.empty();
}
} else {
throw new RuntimeException("Failed");
}
});
}