首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何使用RxJava处理分页?

如何使用RxJava处理分页?
EN

Stack Overflow用户
提问于 2014-10-12 09:41:55
回答 4查看 7.5K关注 0票数 18

我正在考虑将我的android应用程序转换为使用Rxjava来处理网络请求。我目前访问的webservice服务类似于:

代码语言:javascript
复制
getUsersByKeyword(String query, int limit, int offset)

据我所知,观察体是一个“推”而不是“拉”的界面。所以我是这样理解事情的:

  • 应用程序向服务注册,获取可观察的查询
  • 结果被推送到应用程序
  • 应用程序在应用程序需要更多结果时处理结果
  • ...?

这就是我的问题所在。以前我只会向webservice询问我到底想要什么,再次使用偏移量进行查询。但在这种情况下,这将涉及到创建另一个可观察对象并订阅它,这有点违背了要点。

我应该如何处理我的应用程序中的分页?(这是一个android应用程序,但我不认为这是相关的)。

EN

回答 4

Stack Overflow用户

发布于 2015-08-11 16:41:19

这是硬摇滚!)所以我们有对网络的请求:

getUsersByKeyword(String query, int limit, int offset)

例如,此请求返回

List< Result >

如果我们使用RetroFit进行联网,该请求将如下所示:

Observable< List< Result >> getUsersByKeyword(String query, int limit, int offset)

因此,我们希望从服务器获取所有Result

所以它看起来就像这样

代码语言:javascript
复制
int page = 50;
int limit = page;
Observable
                .range(0, Integer.MAX_VALUE - 1)
                .concatMap(new Func1<Integer, Observable<List<Result>>>() {
                    @Override
                    public Observable<List<Result>> call(Integer integer) {
                        return getUsersByKeyword(query, integer * page, limit);
                    }
                })
                .takeWhile(new Func1<List<Result>, Boolean>() {
                    @Override
                    public Boolean call(List<Result> results) {
                        return !results.isEmpty();
                    }
                })
                .scan(new Func2< List<Result>, List<Result>, List<Result>>() {
                    @Override
                    public List<Result> call(List<Result> results, List< Result> results2) {
                        List<Result> list = new ArrayList<>();
                        list.addAll(results);
                        list.addAll(results2);
                        return list;
                    }
                })
                .last()
                .subscribe(new Subscriber<List<Result>>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(List<Results> results) {
                    }
                });

代码已经测试过了!

票数 10
EN

Stack Overflow用户

发布于 2015-01-20 11:43:08

因此,如果这是单向分页,下面是一种您可以尝试的模式。这段代码尚未运行或编译,但我已经尝试过过度注释,以便解释发生了什么。

代码语言:javascript
复制
private static final int LIMIT = 50;

// Given: Returns a stream of dummy event objects telling us when
// to grab the next page. This could be from a click or wherever.
Observable<NextPageEvent> getNextPageEvents();  

// Given:
// The search query keywords. Each emission here means a new top-level
// request;
Observable<String> queries;

queries.switchMap((query) -> getNextPageEvents()
        // Ignore 'next page' pokes when unable to take them.
        .onBackPressureDrop()
        // Seed with the first page.
        .startWith(new NextPageEvent())
        // Increment the page number on each request.
        .scan(0, (page, event) -> page + 1) 
        // Request the page from the server.
        .concatMap((page) -> getUsersByKeyword(query, LIMIT, LIMIT * page)
                // Unroll Observable<List<User> into Observable<User>
                .concatMap((userList) -> Observable.from(userList))
                .retryWhen(/** Insert your favorite retry logic here. */))
        // Only process new page requests sequentially.
        .scheduleOn(Schedulers.trampoline())
        // Trampoline schedules on the 'current thread', so we make sure that's
        // a background IO thread.
        .scheduleOn(Schedulers.io());

这应该会让“下一页事件”信号每次都会触发下一页数据的加载,并且在加载页面时遇到错误时不会跳转页面。如果它接收到新的搜索查询,它还会在顶级完全重新启动。如果我(或其他人?)有时间,我想检查一下我对弹床和背压的假设,并确保它阻止了在加载页面时过早获取下一个页面的任何尝试。

票数 5
EN

Stack Overflow用户

发布于 2014-10-13 02:42:09

我已经这样做了,实际上并不是那么难。

方法是对firstRequestsObservable中的每个第一个请求(偏移量为0)进行建模。为了简单起见,您可以将其作为PublishSubject,在其中调用onNext()以提供下一个请求,但还有更智能的非主题方法(例如,如果在单击按钮时完成请求,则requestObservable是通过某些操作符映射的clickObservable )。

一旦您有了firstRequestsObservable,您就可以从firstRequestsObservable通过flatMapping执行responseObservable,依此类推,以进行服务调用。

现在诀窍来了:创建另一个从responseObservable映射的名为subsequentRequestsObservable的可观察对象,增加偏移量(为此,最好在响应数据中包括原始请求的偏移量)。引入此可观察对象后,现在必须更改responseObservable的定义,以便它也依赖于subsequentRequestsObservable。然后,您将获得一个循环依赖,如下所示:

firstRequestsObservable -> responseObservable -> subsequentRequestsObservable -> responseObservable -> subsequentRequestsObservable -> ...

要打破这个循环,您可能希望在subsequentRequestsObservable的定义中包含一个filter运算符,过滤掉偏移量将超过“总”限制的情况。循环依赖还意味着您需要将其中一个作为主题,否则将无法声明可观察对象。我推荐responseObservable作为这个主题。

因此,总而言之,您首先将responseObservable初始化为一个主题,然后声明firstRequestsObservable,然后将subsequentRequestsObservable声明为通过某些运算符传递responseObservable的结果。然后,可以通过使用onNext来“输入”responseObservable。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26321023

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档