Обработка пейджинга с помощью RxJava

Я использую Retrofit + RxJava в приложении для Android и задаю себе вопрос о том, как обрабатывать разбиение на страницы API на цепочку вызовов до тех пор, пока все данные не будут восстановлены. Что-то вроде этого:

Observable<ApiResponse> getResults(@Query("page") int page); 

Объект ApiResponse имеет простую структуру:

 class ApiResponse { int current; Integer next; List<ResponseObject> results; } 

API вернет следующее значение до последней страницы.

Есть ли хороший способ добиться этого? Пытался объединить некоторые flatMaps () , но не имел успеха.

Solutions Collecting From Web of "Обработка пейджинга с помощью RxJava"

Вы можете моделировать его рекурсивно:

 Observable<ApiResponse> getPageAndNext(int page) { return getResults(page) .concatMap(new Func1<ApiResponse, Observable<ApiResponse>>() { @Override public Observable<ApiResponse> call(ApiResponse response) { // Terminal case. if (response.next == null) { return Observable.just(response); } return Observable.just(response) .concatWith(getPageAndNext(response.next)); } }); } 

Затем, чтобы уничтожить его,

 getPageAndNext(0) .concatMap(new Func1<ApiResponse, Observable<ResponseObject>>() { @Override public Observable<ResponseObject> call(ApiResponse response) { return Observable.from(response.results); } }) .subscribe(new Action1<ResponseObject>() { /** Do something with it */ }); 

Это должно дать вам поток ResponseObject , который поступит по порядку, и, скорее всего, придет в куски размера страницы.

Я ответил на свое решение в аналогичной должности: https://stackoverflow.com/a/34378263/143733

Трюк или поправка к решению, предоставленному @Iopar, – это включение «триггера», наблюдаемого, которое может быть выбрано различными способами.

В опубликованном мной коде он выдается после обработки полной страницы элементов, однако это может произойти и на основе щелчка пользователем кнопки / прокрутки.

Иопар дал отличный пример.

Просто небольшое дополнение.
Если вы хотите получить все страницы в одном вызове onNext ().
Это может быть полезно, если вы хотите закрепить этот результат еще одним наблюдаемым.
Вы должны написать:

 private List<String> list = new LinkedList() { { add("a"); add("b"); add("c"); } }; int count = 1; public Observable<List<String>> getAllStrings(int c) { return Observable.just(list) .concatMap( strings -> { if (c == 3) { return Observable.just(list); } else { count += 1; return Observable.zip( Observable.just(list), getAllStrings(count), (strings1, strings2) -> { strings1.addAll(strings2); return strings1; } ); } } ); } 

Использование :

 getAllStrings(0) .subscribe(strings -> { Log.w(TAG, "call: " + strings); }); 

И вы получите:

 call: [a, b, c, a, b, c, a, b, c, a, b, c]