RxJava - 结合concat和merge但检查ALL concated observable

时间:2015-10-23 06:55:06

标签: java android merge concat rx-java

我正在从多个来源加载数据并缓存它们。

我的工作如下:

  • 从多个来源加载数据
  • 将结果缓存到内存中

我想要的是:

  1. 加载所有需要的数据
  2. 连接结果,仅在所有数据可用时传播结果
  3. 一个简单的例子如下:

    mObservable1 = Observable
        .concat(mObservable1Cached, mObservable1)
        .first();
    

    如何组合许多缓存而不是上面示例中的缓存可观察量只有1?这是我的想法,但这不起作用,因为只要两个observable中的一个有缓存数据,它就会传播结果......

    mObservable1And2  = Observable
        .concat(
                Observable.merge(mObservable1Cached, mObservable2Cached),
                Observable.merge(mObservable1, mObservable2)
        )
        .first();
    

    Observables示例

    缓存数据可观察

    mObservable1Cached = Observable.create(new Observable.OnSubscribe<List<Data>>() {
        @Override
        public void call(Subscriber<? super List<Data>> subscriber) {
            subscriber.onNext(mData1Cached);
            subscriber.onCompleted();
        }
    })
            .subscribeOn(HandlerScheduler.from(mBackgroundHandler))
            .observeOn(AndroidSchedulers.mainThread());
    

    加载数据可观察

    mObservable1 = Observable.create(new Observable.OnSubscribe<List<Data>>() {
            @Override
            public void call(Subscriber<? super List<Data>> subscriber) {
                subscriber.onNext(...load data...);
                subscriber.onCompleted();
            }
        })
        .doOnNext(new Action1<List<Data>>() {
            @Override
            public void call(List<Data> data) {
                mData1Cached = data;
            }
        })
        .subscribeOn(HandlerScheduler.from(mBackgroundHandler))
        .observeOn(AndroidSchedulers.mainThread());
    

3 个答案:

答案 0 :(得分:0)

这与rx模式类似,如何获得表单提交。使用包含2个表单字段的UI时,只需要在两个表单都存在时启用提交按钮。 RxJava允许您使用combineLatest运算符执行此操作。每当一个observable发出一个项目时,它将与另一个发射的observable中的最后一个发射项目组合在一起。如果到目前为止只发出一个observable,它会等待另一个observable发出,然后传递这两个值。

CombineLatest是我对如何使其发挥作用的猜测。

答案 1 :(得分:0)

zip()可以解决问题。

这是完整的(java8)解决方案。 如果你受到java7的限制,重构的重要性就是认为它会更加冗长。 使用zip还可以处理任意数量的源(不仅仅是固定数量)。

mail

输出:

  //Dummy data
  static class Data {
    static Map<String, AtomicInteger> dataVersion = new ConcurrentHashMap<>();
    int sourceId;
    int itemId;
    int version;

    Data(int sourceId, int itemId) {
      this.sourceId = sourceId;
      this.itemId = itemId;
      //for testing purpose we going to track how many items created for each source/item pair
      //we always expect one
      AtomicInteger versionCounter = dataVersion.computeIfAbsent(sourceId + "." + itemId, key->new AtomicInteger());
      this.version = versionCounter.incrementAndGet();
    }
    public String toString() {
      return sourceId + "." + itemId + "; version: " + version;
    }
  };

  //data cache (per source)
  ConcurrentMap<Integer, List<Data>> sourceCache = new ConcurrentHashMap<>();

  //data loader
  List<Data> loadData(int sourceId) {
    return Arrays.asList(new Data(sourceId,1), new Data(sourceId,2), new Data(sourceId,3));
  }

  //source observable factory method
  Observable<List<Data>> getSource(int sourceId) {
    return Observable.<List<Data>>create(subscriber->{
      subscriber.onNext(sourceCache.computeIfAbsent(sourceId, key->loadData(key)));
      subscriber.onCompleted();
    });
  }

  public void stackOverflow33296442() {

    Observable<List<Data>> result = Observable.zip(getSource(1), getSource(2), (src1,src2)->Arrays.asList(src1,src2))
        .concatMap(listOfLists->Observable.from(listOfLists));

    //Test
    Iterator<List<Data>> iter1 = result.toBlocking().toIterable().iterator();
    while (iter1.hasNext()) {
      List<Data> next = iter1.next();
      System.out.println("data: " + next);
      for (Data data : next) {
        assert 1 == data.version;
      }
    }

    Iterator<List<Data>> iter2 = result.toBlocking().toIterable().iterator();
    while (iter2.hasNext()) {
      List<Data> next = iter2.next();
      System.out.println("data: " + next);
      for (Data data : next) {
        assert 1 == data.version;
      }
    }
  }

答案 2 :(得分:0)

你要求阻塞直到完成连接的可观察量,这可以像这样实现:

onClick()