Angel Koh
Angel Koh

Reputation: 13485

How to iterate a Flowable from the result of a Single

I am using Retrofit with Rxjava to retrieve a Single response.

@GET("/commonapi/search")
Single<MyEntity> requestAddressRx(@Query("searchVal") String searchVal,
                                   @Query("pageNum") int pageNum);

I have a json that will return the following

{"found":240,"totalNumPages":16,"pageNum":1,"results":[...

Currently, to retrieve all 16 pages, I have to do the following: -

  1. call requestAddressRx() one time to get the 1st result for the totalNumPages,
  2. and then create a separate Flowable calling requestAddressRx() to loop from page 2 to 16.

Is there a way where I can combine step 1 and 2 together?


//After some bumbling around - what i currently have is

    Single<List<MyEntity>> result =  addressRetrofitRx.requestAddressQueryRx(query, 1)
            //now i get the number of pages from the results
            //  -NOTE: the result is now discarded :(
            .map( r-> r.getTotalNumPages() ) 
            //now i create a flowable from the number of pages
            .flatMapPublisher(totalNumPages -> Flowable.range(1, totalNumPages))
            .flatMapSingle(pageNumber -> addressRetrofitRx.requestAddressQueryRx(query, pageNumber))
            .toList();

This causes Rxjava to call page 1 twice (the first time is read and discarded after I read the totalNumPages).

Also if the result only have 1 totalNumPages, I will still spawn the flowable.

There ought to be a better way to approach this problem, but I can't seem to figure it out. JSON schemas where the numberOfPages is encoded in the result are very common, so I assumed there's a correct RxJava way of parsing them.

Upvotes: 1

Views: 1226

Answers (1)

akarnokd
akarnokd

Reputation: 69997

You don't have to map out the total number of pages, just concat the first page's MyEntity with the rest of the pages:

Single<List<MyEntity>> result =  api.requestAddressQueryRx(query, 1)
    //now i create a flowable from the number of pages
    .flatMapPublisher(r -> {
         Flowable<MyEntity> pages = Flowable.just(r);
         int maxPages = r.getTotalNumPages();
         if (maxPages > 1) {
             pages = pages
                 .concatWith(
                     Flowable.range(2, maxPages - 1)
                         .flatMapSingle(pageNumber ->
                             api.requestAddressQueryRx(query, pageNumber)
                         , /* eager error */ false, /* keep order of pages */ 1)
                 );
         }
         return pages;
     })
     .toList();

Upvotes: 1

Related Questions