使用Retrofit2 / RxJava和Single进行分页

时间:2018-10-03 10:54:29

标签: retrofit2 rx-java2 data-paging

我正在尝试为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");
                }
            });
}

0 个答案:

没有答案