RxJava Pagination

前端 未结 1 779
刺人心
刺人心 2021-02-04 22:19

I am fairly new to rxJava. in my api response, I get information about total number of pages and current page number like:

 \"pages\": 22,
 \"page\": 1,
<         


        
1条回答
  •  不思量自难忘°
    2021-02-04 23:18

    I'll paste below the solution I'm using - which also uses Retrofit. In the example below, I'm using Retrofit to create an Observable of all public repositories from the GitHub API.

    I believe the trick here is that I am recursing on the Observable and concatenating with another Observable is essentially a trigger.

    This trigger can emit a variety of ways (perhaps when the user scrolls to the bottom of the page) however in this example, it immediately emits once a full page has been handled.

    /***
     * This is a helper wrapper Subscriber that helps you lazily defer
     * continuous paging of a result set from some API.
     * Through the use of a {@link Subject}, it helps notify the original {@link Observable}
     * when to perform an additional fetch.
     * The notification is sent when a certain count of items has been reached.
     * Generally this count represents the page.
     * @param  The event type
     */
    @Data
    public class PagingSubscriber extends Subscriber {
    
        private final Subject nextPageTrigger = PublishSubject.create();
        private final long pageSize;
        private long count = 0;
        private final Subscriber delegate;
    
        /***
         * Creates the {@link PagingSubscriber}
         * @param pageSize
         * @param delegate
         */
        public PagingSubscriber(long pageSize, Subscriber delegate) {
            this.pageSize = pageSize;
            this.delegate = delegate;
        }
    
        public Observable getNextPageTrigger() {
            return nextPageTrigger;
        }
    
        @Override
        public void onStart() {
            delegate.onStart();
        }
    
        @Override
        public void onCompleted() {
            delegate.onCompleted();
        }
    
        @Override
        public void onError(Throwable e) {
            delegate.onError(e);
        }
    
        @Override
        public void onNext(T t) {
            count+=1;
            if (count == pageSize) {
                nextPageTrigger.onNext(null);
                count= 0;
            }
            delegate.onNext(t);
        }
    
    }
    
    @Data
    public class GitHubRepositoryApplication {
    
        private final GitHubService gitHubService;
    
        @Inject
        public GitHubRepositoryApplication(GitHubService githubService) {
            this.gitHubService = githubService;
        }
    
        public Observable printAllRepositories(Observable nextPageTrigger) {
            return printRepositoryPages(GitHubService.FIRST_PAGE, nextPageTrigger)
                    .flatMapIterable(r -> r.body());
        }
    
    
        public Observable>> printRepositoryPages(String startingPage, Observable nextPageTrigger) {
            return gitHubService.listRepos(startingPage)
                    .concatMap(response -> {
                        Optional nextPage = Optional.ofNullable(response.headers().get(HttpHeaders.LINK))
                                .flatMap(header -> GitHubServiceUtils.getNextToken(header));
    
                        if (!nextPage.isPresent()) {
                            return Observable.just(response);
                        }
                        return Observable.just(response)
                                .concatWith(nextPageTrigger.limit(1).ignoreElements().cast(Response.class))
                                .concatWith(printRepositoryPages(nextPage.get(), nextPageTrigger));
                    });
        }
    
        public static void main(String[] args) {
            Injector injector = Guice.createInjector(new GitHubModule());
    
            GitHubRepositoryApplication app = injector.getInstance(GitHubRepositoryApplication.class);
    
            Subscriber subscriber = new Subscriber() {
    
                private final Logger log = LoggerFactory.getLogger(getClass());
    
                @Override
                public void onStart() {
                    log.debug("STARTING");
                    request(1l);//we need to begin the request
                }
    
                @Override
                public void onCompleted() {
                    log.debug("COMPLETED");
                }
    
                @Override
                public void onError(Throwable e) {
                    log.error("ERROR",e);
                }
    
                @Override
                public void onNext(GitHubRepository gitHubRepository) {
                    log.debug("{}",gitHubRepository);
                    request(1l);//we need to make sure we have asked for another element
                }
            };
    
            PagingSubscriber pagingSubscriber = new PagingSubscriber<>(GitHubService.PAGE_SIZE, subscriber);
    
            //In order for the JVM not to quit out, we make sure we turn our Observable to
            //a BlockingObservable, so that all of it will finish.
            Observable observable =
                    app.printAllRepositories(pagingSubscriber.getNextPageTrigger());
            observable.toBlocking().subscribe(pagingSubscriber);
    
        }
    
    }
    

    0 讨论(0)
提交回复
热议问题