如何处理RxJava的分页?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (20)

我正在考虑将我的android应用程序转换为使用Rxjava进行网络请求。我目前访问类似于以下的web服务:

getUsersByKeyword(String query, int limit, int offset)

据我所知,Observable是一个“push”而不是“pull”的界面。所以这里是我理解事情的方法:

  • 应用程序注册服务,获取查询的Observable
  • 结果被推送到应用程序
  • 应用程序处理结果
  • 当应用程序想要更多结果...?

这是事情为我分解的地方。以前,我只是问Web服务正是我想要的,再次使用偏移量进行查询。但是在这种情况下,会涉及到创建另一个Observable并订阅它,这种方式会破坏这一点。

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

提问于
用户回答回答于

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

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());

这应该让'下一页事件'信号每次触发下一页数据的加载,以及在加载页面时遇到错误时不跳转页面。如果它收到新的搜索查询,它也会从顶层完全重新启动。如果我(或其他人?)有时间,我想检查一下我对蹦床和背压的假设,并确保它阻止任何试图在加载时提前取下一页的尝试。

用户回答回答于

我们有网络请求: getUsersByKeyword(String query, int limit, int offset) 并且这个请求返回例如 List< Result > 如果我们使用RetroFit进行网络连接,请求将看起来: Observable< List< Result >> getUsersByKeyword(String query, int limit, int offset) 因为我们希望Result从服务器获取全部内容。 所以它看起来像这样

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) {
                    }
                });

代码已经过测试!

扫码关注云+社区