Переполнение стека при использовании Retrofit rxjava concatWith

Я хочу обрабатывать нумерацию страниц в Retrofit, используя rxjava Observable. Я последовал совету из другого вопроса.

У меня есть более 100 страниц, которые необходимо получить, но цепочка завершается сбоем около 20-й страницы и останавливает любую дальнейшую подписку на наблюдаемую с помощью приведенного ниже журнала в logcat.

04-04 04:12:11.766    2951-3012/com.example.app I/dalvikvm﹕ threadid=28: stack overflow on call to Ljava/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater;.compareAndSet:ZLJJ
04-04 04:12:11.766    2951-3012/com.example.app I/dalvikvm﹕ method requires 56+20+32=108 bytes, fp is 0x94b52350 (80 left)
04-04 04:12:11.766    2951-3012/com.example.app I/dalvikvm﹕ expanding stack end (0x94b52300 to 0x94b52000)
04-04 04:12:11.766    2951-3012/com.example.app I/dalvikvm﹕ Shrank stack (to 0x94b52300, curFrame is 0x94b548dc)

Кто-нибудь знает, почему это может произойти?

Обновление: я знаю, что это происходит из-за рекурсии, но есть ли более изящный способ обработки нумерации страниц с помощью модификации и rxjava?


person Bhuvan    schedule 04.04.2015    source источник
comment
Возможный дубликат Paginate Observable результатов без рекурсии - RxJava   -  person Adam Millerchip    schedule 15.08.2018


Ответы (1)


Итак, учитывая, что я ответил на исходный вопрос, на который вы ссылались, я, вероятно, должен попытаться ответить и на этот случай. :)

Это еще одна действительная (и потенциально более простая) альтернатива моему первоначальному ответу на пейджинг, теперь, когда я разработал еще несколько приемов Rx в своем арсенале. :) (сделано в псевдокоде в стиле лямбда java8):

Observable.range(Integer.MAX_VALUE)
    // Get each page in order.
    .concatMap(page -> getResults(page))
    // Take every result up to and including the one where the next page index is null.
    .takeUntil(result -> result.next == null)
    // Add each output to a list builder. I'm using Guava's ImmutableList, but you could
    // just as easily use a regular ArrayList and avoid having to map afterwards. I just
    // personally prefer outputting an immutable data structure, and using the builder
    // is natural for this.
    //
    // Also, if you wanted to have the observable stream the full output at each page,
    // you could use collect instead of reduce. Note it has a slightly different syntax. 
    .reduce(
        ImmutableList.<ResponseObject>builder(),
        (builder, response) -> builder.addAll(response.results))
    // Convert list builder to one List<ResponseObject> of all the things.
    .map(builder -> builder.build())
    .subscribe(results -> { /* Do something with results. */ });
person lopar    schedule 12.04.2015
comment
Наконец-то добрался до этого... Придумал аналогичный подход и заработал :) - person Bhuvan; 05.06.2015
comment
Шикарный код! Думаю, теперь Observable.range тоже нужен int start! - person Kayan Almeida; 30.08.2016
comment
Допустим, у меня есть 1000 страниц, это возможно/хорошо? - person Ajinkya; 17.07.2017
comment
Это не работает, если getResults(page) подписывается на другой планировщик. Совершенно недетерминированное поведение на тот момент. - person AutonomousApps; 25.05.2018