如何使用rxjava1.x进行分页,而分页必须调用具有不同数据的每个页面?

如何使用rxjava1.x进行分页,而分页必须调用具有不同数据的每个页面?,java,rx-java,Java,Rx Java,我在这个问题上看到了很多变化。然而,没有一个能完全代表我的情况。我已经做了一个小测试,但我不清楚如何继续实现下面的方法getPages。策略是在第一次调用时调用PageProvider#getPage(null),然后调用PageProvider#getPage(page.next)(其中page是最后一次调用返回的页面),直到page.done()返回true import org.junit.Test; import rx.Observable; import rx.Single; imp

我在这个问题上看到了很多变化。然而,没有一个能完全代表我的情况。我已经做了一个小测试,但我不清楚如何继续实现下面的方法
getPages
。策略是在第一次调用时调用
PageProvider#getPage(null)
,然后调用
PageProvider#getPage(page.next)
(其中
page
是最后一次调用返回的页面),直到
page.done()
返回
true

import org.junit.Test;
import rx.Observable;
import rx.Single;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class RxJava1TakeUntilTest {
  PageProvider provider = new PageProvider(3);

  Observable<PageProvider.Page> getPages() {
    // TODO: call provider.getPage(null) then provider.getPage(page.next) until page.done() is true
    return null;
  }

  @Test
  public void testTakeUntil() {
    getPages().subscribe(page -> System.out.println(page.toString()));
  }

  public static class PageProvider {
    public static class Page {
      public String current;
      public String next; // is null if no more pages

      public Page(String current, String next) {
        this.current = current;
        this.next = next;
      }

      public boolean done() {
        return next == null;
      }

      @Override
      public String toString() {
        return current + " -> " + next;
      }
    }

    int pageCount;
    Page firstPage;
    Map<String, Page> pages = new HashMap<>();

    public PageProvider(int pageCount) {
      this.pageCount = pageCount;
      for (int i = 0; i < pageCount; i++) {
        Page page = new Page(uuid(), i == pageCount - 1 ? null : uuid());
        if (i == 0) firstPage = page;
        pages.put(page.current, page);
      }
    }

    public Single<Page> getPage(String index) {
      return Single.just(index == null ? firstPage : pages.get(index));
    }

    static String uuid() {
      return UUID.randomUUID().toString();
    }
  }
}

提前感谢。

我认为最简单的方法是让您的页面提供者实现
Iterable
并返回一个按顺序遍历页面的
迭代器。一旦你有了它,你就可以从(pageProvider)
简单地执行
Observable.from。这里的优点是,如果您愿意,还可以使用Java的原生
forEach

或者,您可以使用
Observable。创建
并使用
onNext
将您的项目逐个推入其中,最后调用
onComplete


最后,如果您不关心顺序,或者您将
Map
更改为一个有序的,您可以简单地执行
Observable.from(Map.values())

我认为最简单的事情是让您的页面提供者实现
Iterable
并返回一个按顺序遍历页面的
迭代器。一旦你有了它,你就可以从(pageProvider)
简单地执行
Observable.from。这里的优点是,如果您愿意,还可以使用Java的原生
forEach

或者,您可以使用
Observable。创建
并使用
onNext
将您的项目逐个推入其中,最后调用
onComplete


最后,如果您不关心顺序,或者将
映射
更改为有序映射,您只需执行
可观察的.from(Map.values())

页面提供程序
实现不正确(您的页面未链接),但一旦修复,您可以使用

Observable<PageProvider.Page> getPages() {
    BehaviorSubject<String> pageControl = BehaviorSubject.create((String)null);
    Observable<PageProvider.Page> ret = pageControl.asObservable()
            .concatMap(apageIndex ->
                       provider.getPage(apageIndex).toObservable().doOnNext(
                               page-> {
                                   if (page.next == null)
                                       pageControl.onCompleted();
                                   else
                                       pageControl.onNext(page.next);
                               }));
    return ret;
}
可观察的getPages(){
BehaviorSubject pageControl=BehaviorSubject.create((字符串)null);
可观测ret=pageControl.asObservable()
.concatMap(apageIndex->
provider.getPage(apageIndex.toObservable().doOnNext(
第->{
如果(page.next==null)
pageControl.onCompleted();
其他的
pageControl.onNext(page.next);
}));
返回ret;
}

页面提供程序的实现不正确(您的页面未链接),但一旦修复,您可以使用

Observable<PageProvider.Page> getPages() {
    BehaviorSubject<String> pageControl = BehaviorSubject.create((String)null);
    Observable<PageProvider.Page> ret = pageControl.asObservable()
            .concatMap(apageIndex ->
                       provider.getPage(apageIndex).toObservable().doOnNext(
                               page-> {
                                   if (page.next == null)
                                       pageControl.onCompleted();
                                   else
                                       pageControl.onNext(page.next);
                               }));
    return ret;
}
可观察的getPages(){
BehaviorSubject pageControl=BehaviorSubject.create((字符串)null);
可观测ret=pageControl.asObservable()
.concatMap(apageIndex->
provider.getPage(apageIndex.toObservable().doOnNext(
第->{
如果(page.next==null)
pageControl.onCompleted();
其他的
pageControl.onNext(page.next);
}));
返回ret;
}
我也有类似的问题()

一个可能的解决方案是这样的

Flowable<Page> getPages() {
    // TODO: call provider.getPage(null) then provider.getPage(page.next) until page.done() is true
    AtomicReference<Page> ref = new AtomicReference<>();

    return Flowable.just(ref)
                   .map(AtomicReference::get) // get the current page
                   .map(page -> page.next)    // get the next index
                   .flatMapSingle(index -> provider.getPage(index)) // get the next page
                   .doOnNext(ref::set)
                   .repeatUntil(() -> ref.get() != null && ref.get().done())
                   .startWith(provider.getPage(null) // deal with 1st page
                                      .toFlowable()
                                      .doOnNext(ref::set))
                    ;
}
可流动的getPages(){
//TODO:调用provider.getPage(null),然后调用provider.getPage(page.next),直到page.done()为true
AtomicReference ref=新的AtomicReference();
返回可流动。仅(参考)
.map(AtomicReference::get)//获取当前页面
.map(page->page.next)//获取下一个索引
.flatMapSingle(index->provider.getPage(index))//获取下一页
.doOnNext(参考::集)
.repeatUntil(()->ref.get()!=null&&ref.get().done())
.startWith(provider.getPage(null)//处理第一页
.toFlowable()
.doOnNext(参考::集))
;
}
不确定这是不是最好的解决方案,但我希望它能有所帮助。

我也遇到过类似的问题()

一个可能的解决方案是这样的

Flowable<Page> getPages() {
    // TODO: call provider.getPage(null) then provider.getPage(page.next) until page.done() is true
    AtomicReference<Page> ref = new AtomicReference<>();

    return Flowable.just(ref)
                   .map(AtomicReference::get) // get the current page
                   .map(page -> page.next)    // get the next index
                   .flatMapSingle(index -> provider.getPage(index)) // get the next page
                   .doOnNext(ref::set)
                   .repeatUntil(() -> ref.get() != null && ref.get().done())
                   .startWith(provider.getPage(null) // deal with 1st page
                                      .toFlowable()
                                      .doOnNext(ref::set))
                    ;
}
可流动的getPages(){
//TODO:调用provider.getPage(null),然后调用provider.getPage(page.next),直到page.done()为true
AtomicReference ref=新的AtomicReference();
返回可流动。仅(参考)
.map(AtomicReference::get)//获取当前页面
.map(page->page.next)//获取下一个索引
.flatMapSingle(index->provider.getPage(index))//获取下一页
.doOnNext(参考::集)
.repeatUntil(()->ref.get()!=null&&ref.get().done())
.startWith(provider.getPage(null)//处理第一页
.toFlowable()
.doOnNext(参考::集))
;
}
不确定这是不是最好的解决方案,但我希望它能有所帮助。

NB:虽然这是一个答案,但我不相信这是最好的

下面是我如何解决它的(所有代码,包括一个新的测试,以确保
PageProvider
正常工作)。这与@ctranxuan的答案类似。我当然愿意接受改进建议。我不喜欢的部分是使用
AtomicReference
get()
&
set(…)
对性能的潜在影响

import org.junit.Test;
进口接收。可观察;
进口接收单;
导入java.util.HashMap;
导入java.util.Map;
导入java.util.UUID;
导入java.util.concurrent.AtomicReference;
导入静态org.junit.Assert.as
 AtomicReference<Page> ref = new AtomicReference<>();

 return Observable.just(ref)
                  .map(AtomicReference::get) // get the current page
                  .map(page -> page.next)    // get the next index
                  .flatMapSingle(index -> provider.getPage(index)) // get the next page
                  .doOnNext(ref::set)
                  .repeat()
                  .takeUntil(Page::done)
                  .startWith(provider.getPage(null) // deal with 1st page
                                     .toObservable()
                                     .doOnNext(ref::set))
            ;
Observable<Page> getPages() {
   AsyncOnSubscribe<Page, Page> stateful =
       AsyncOnSubscribe.createStateful(() -> provider.getPageFrom(null),
                                       (page, requested, observer) -> {
                                             if (!page.done()) {
                                                 observer.onNext(Observable.just(page));
                                             }
                                             return provider.getPageFrom(page.next);
                                      });
    return Observable.create(stateful);
}
...
public static class PageProvider {
    public Page getPageFrom(String index) {
        return index == null ? firstPage : pages.get(index);
    }
}