我该如何使用RxJava 1.x来对页面进行调用,直到页面必须调用具有不同数据的页面?

时间:2018-07-18 13:53:45

标签: java rx-java

关于SO,我在这个问题上看到了许多变化。但是,没有什么能代表我的情况。我已经进行了一些测试,但是还不清楚如何继续执行下面的方法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();
    }
  }
}

如果要创建一个快速的Java项目,下面是一个build.gradle文件:

plugins {
  id 'java-library'
}
repositories {
  mavenCentral()
}
dependencies {
  compile 'io.reactivex:rxjava:1.3.8'

  testCompile 'junit:junit:4.12'
}

谢谢。

6 个答案:

答案 0 :(得分:1)

PageProvider的实现不正确(您的页面未链接),但是一旦修复,您可以使用来实现分页

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

答案 1 :(得分:1)

我遇到了类似的问题(https://github.com/ctranxuan/howtos-rxjava/blob/master/src/main/java/org/ws13/howtos/rxjava/pagination/HowToHandlePagination.java)。

一种可能的解决方案是类似的东西?

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

不确定这是最好的解决方案,但希望对您有所帮助。

答案 2 :(得分:1)

抱歉,我错过了RxJava 1.x没有操作符repeatUntil()。但这可以通过将repeat()takeUntil()组合来解决。 在这里:

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

答案 3 :(得分:0)

我认为最简单的方法是让您的PageProvider实现Iterable并返回按顺序遍历页面的Iterator<Page>。有了这些后,就可以简单地进行Observable.from(pageProvider)。这样做的好处是,如果您愿意,也可以使用Java的本机forEach

或者,您可以使用Observable.create,并使用onNext并最终调用onComplete将项目逐项放入其中。

最后,如果您不关心订单,或者将Map更改为订购的商品,则只需执行Observable.from(map.values())

答案 4 :(得分:0)

NB:虽然这是一个答案,但我不认为这是最好的。

这是我解决的方式(所有代码,包括一项新测试,以确保PageProvider正常运行)。这类似于@ctranxuan的答案。我绝对愿意提出改进建议。我不喜欢的部分是使用AtomicReference get()set(..)可能会对性能产生影响。

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

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

public class RxJava1TakeUntilTest {

  @Test
  public void testCountNumberOfPages() {
    int count = 3;
    PageProvider provider = new PageProvider(count);
    AtomicReference<PageProvider.Page> holder = new AtomicReference<>(null);

    Observable.just(holder) // reference to holder of current page
        .repeat() // repeat forever
        .flatMapSingle( // get a page
            it -> {
              PageProvider.Page page = it.get();
              return provider.getPage(page == null ? null : page.next);
            })
        .map( // update holder to latest response
            page -> {
              holder.set(page);
              return page;
            })
        .takeUntil(page -> page.done())
        .reduce(0, (total, page) -> total + 1)
        .test()
        .assertResult(count);
  }

  @Test
  public void testPageProvider() {
    PageProvider provider = new PageProvider(2);
    provider
        .getPage(null)
        .map(
            page -> {
              assertNotNull(page);
              assertNotNull(page.current);
              assertNotNull(page.next);
              return page.next;
            })
        .flatMap(provider::getPage)
        .map(
            page -> {
              assertNotNull(page);
              assertNotNull(page.current);
              assertNull(page.next);
              return page;
            })
        .test()
        .assertNoErrors();
  }

  public static class PageProvider {
    int pageCount;
    Page firstPage;
    Map<String, Page> pages = new HashMap<>();

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

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

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

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

答案 5 :(得分:0)

另一种可能的解决方案是使用echo '<option value="'. htmlspecialchars($username) .'">'. htmlspecialchars("$type $username $Lastname") .'</option>';

Observable.create()

...在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); } } 中做了些微更改。 但是在这种情况下,您正在创建一些PageProvider(与页面数一样多)。