Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 异步、早期退出、串联可观察_Algorithm_Rx Java - Fatal编程技术网

Algorithm 异步、早期退出、串联可观察

Algorithm 异步、早期退出、串联可观察,algorithm,rx-java,Algorithm,Rx Java,假设我们有3个可观察对象,A、B和C。对于外行来说,我需要同时异步运行所有3个,但是: 如果我从A得到任何东西,发射它。。。不要发射任何其他东西。 如果A完成而不发出任何信息,则将规则1应用于B。 如果B完成而没有发出任何东西,则从C发出项。 如果C完成而没有发出任何东西,则发出一个默认项。 昨天我花了几个小时试图弄明白这一点,而RxJava中似乎还没有任何操作组合可以让我做到这一点 您可以考虑从左到右级联的值: A->B->C 此外,级联被阻塞,而每个级联都异步运行并缓存其值 A nothin

假设我们有3个可观察对象,A、B和C。对于外行来说,我需要同时异步运行所有3个,但是:

如果我从A得到任何东西,发射它。。。不要发射任何其他东西。 如果A完成而不发出任何信息,则将规则1应用于B。 如果B完成而没有发出任何东西,则从C发出项。 如果C完成而没有发出任何东西,则发出一个默认项。 昨天我花了几个小时试图弄明白这一点,而RxJava中似乎还没有任何操作组合可以让我做到这一点

您可以考虑从左到右级联的值:

A->B->C

此外,级联被阻塞,而每个级联都异步运行并缓存其值

A nothing->B nothing->C nothing->默认项

为了清楚起见,在任何其他观察者发出任何信号之前,必须先完成A。同样的逻辑对于B,然后对于C,如果A,B,C没有发出任何东西,那么默认的逻辑就是B,C

很明显,这涉及到缓存,我绝对不想在上面重播可观察到的内容。我需要重播缓存的值。在每一个门口都有

这种行为与之极为相似,只是如果之前有排放,则不会释放链条的下一部分

public class ConcatObservable<T> {

private final List<Observable<? extends T>> observables;

private ConcatObservable(List<Observable<? extends T>> observables) {
    this.observables = observables;
}

public static <T> ConcatObservable<T> from(Observable<? extends T>... observables) {
    return new ConcatObservable<T>(Arrays.asList(observables));
}

public Observable<T> asObservable() {
    return Observable.create(new Observable.OnSubscribe<T>() {
        @Override
        public void call(final Subscriber<? super T> subscriber) {
            List<Observable<? extends T>> cachedObservables = new ArrayList<Observable<? extends T>>();
            for (Observable<? extends T> observable : observables) {
                ConnectableObservable<? extends T> replayedObservable = observable.replay();
                cachedObservables.add(replayedObservable);
                subscriber.add(replayedObservable.connect());
            }
            Subscription s = Observable.concat(Observable.from(cachedObservables)).take(1).subscribe(subscriber);
            subscriber.add(s);
        }
    });
}
}
编辑 这已关闭,但未通过以下测试:

@Test @SuppressWarnings("unchecked")
public void it_onlyEmitsFromFirstObservable() {
  Observable<String> A = Observable.from(Arrays.asList("A", "A", "A"));
  Observable<String> B = Observable.from(Arrays.asList("B", "B", "B"));
  Observable<String> C = Observable.from(Arrays.asList("C", "C", "C"));

  Observable<String> observable = ConcatObservable.from(A, B, C).asObservable();

  TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
  observable.subscribe(testSubscriber);

  assertThat(testSubscriber.getOnNextEvents()).containsExactly("A", "A", "A");
}

以下是我的想法:

**
 * Works like {@link rx.Observable#concat} but concatenated Observables
 * are all run immediately on their given {@link rx.Scheduler}.
 *
 * This Observable is blocking in the sense that items are emitted in order
 * like {@link rx.Observable#concat} but since each Observable is run on
 * an (possibly) asynchronous scheduler, items emitted further down the chain
 * of Observables are held until items further up the chain are (possibly) emitted.
 *
 * This Observable also short-circuits and does not emit items further down
 * the chain of Observables when an Observable higher up the chain emits items.
 *
 * For example:
 *
 * Given Observable A, B, and C
 *
 * If A emits item(s) emit them... do not emit anything else.
 * If A completes without emitting anything, apply previous rule to B.
 * If B completes without emitting anything, emit items from C (if any)
 *
 * @param <T>
 */
public class ConcatObservable<T> {
  private final List<Observable<? extends T>> observables;

  private ConcatObservable(List<Observable<? extends T>> observables) {
    this.observables = observables;
  }

  public static <T> ConcatObservable<T> from(Observable<? extends T>... observables) {
    return new ConcatObservable<T>(Arrays.asList(observables));
  }

  public Observable<T> asObservable() {
    final List<Subscription> subscriptions = new CopyOnWriteArrayList<Subscription>();

    return Observable.create(new Observable.OnSubscribe<T>() {
      @Override public void call(final Subscriber<? super T> subscriber) {
        List<Observable<? extends T>> cachedObservables = new ArrayList<Observable<? extends T>>();
        for (Observable<? extends T> observable : observables) {

          // tell it to cache values
          final ReplaySubject<T> subject = ReplaySubject.create();
          cachedObservables.add(subject);

          // run it with nobody listening
          Subscription subscription = observable.subscribe(new Observer<T>() {
            @Override public void onCompleted() {
              subject.onCompleted();
            }

            @Override public void onError(Throwable e) {
              subject.onError(e);
            }

            @Override public void onNext(T item) {
              subject.onNext(item);
            }
          });
          subscriptions.add(subscription);
        }

        final AtomicReference<Throwable> error = new AtomicReference<Throwable>();

        // for the cached ones, already running
        for (Observable<? extends T> observable : cachedObservables) {

          final AtomicBoolean shouldExit = new AtomicBoolean(false);
          final CountDownLatch latch = new CountDownLatch(1);
          Subscription subscription = observable.subscribe(new Observer<T>() {
            @Override public void onCompleted() {
              latch.countDown();
            }

            @Override public void onError(Throwable e) {
              error.set(e);
              shouldExit.set(true);
              latch.countDown();
            }

            @Override public void onNext(T item) {
              subscriber.onNext(item);
              shouldExit.set(true);
            }
          });

          // Track each subscription
          subscriptions.add(subscription);

          try {
            // Wait for this one to stop emitting, or error
            latch.await();
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("Interrupted while waiting for subscription to complete", e);
          }

          // This one had an item(s), so we don't bother with the rest
          if (shouldExit.get()) {
            break;
          }
        }

        // Release inner subscriptions
        for (Subscription subscription : subscriptions) {
          subscription.unsubscribe();
        }

        // Obey the Observable contract...
        Throwable throwable = error.get();
        if (throwable != null) {
          subscriber.onError(throwable);
        } else {
          subscriber.onCompleted();
        }
      }
    });
  }
}
以下是相应的测试:

public class ConcatObservableTest {

  @Test @SuppressWarnings("unchecked")
  public void it_onlyEmitsFromFirstObservable() {
    Observable<String> A = Observable.from(Arrays.asList("A", "A", "A"));
    Observable<String> B = Observable.from(Arrays.asList("B", "B", "B"));
    Observable<String> C = Observable.from(Arrays.asList("C", "C", "C"));

    Observable<String> observable = ConcatObservable.from(A, B, C).asObservable();

    TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
    observable.subscribe(testSubscriber);

    assertThat(testSubscriber.getOnNextEvents()).containsExactly("A", "A", "A");
  }

  @Test @SuppressWarnings("unchecked")
  public void it_onlyEmitsFromSecondObservable() {
    Observable<String> A = Observable.empty();
    Observable<String> B = Observable.from(Arrays.asList("B", "B", "B"));
    Observable<String> C = Observable.from(Arrays.asList("C", "C", "C"));

    Observable<String> observable = ConcatObservable.from(A, B, C).asObservable();

    TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
    observable.subscribe(testSubscriber);

    assertThat(testSubscriber.getOnNextEvents()).containsExactly("B", "B", "B");
  }

  @Test @SuppressWarnings("unchecked")
  public void it_onlyEmitsFromLastObservable() {
    Observable<String> A = Observable.empty();
    Observable<String> B = Observable.empty();
    Observable<String> C = Observable.from(Arrays.asList("C", "C", "C"));

    Observable<String> observable = ConcatObservable.from(A, B, C).asObservable();

    TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
    observable.subscribe(testSubscriber);

    assertThat(testSubscriber.getOnNextEvents()).containsExactly("C", "C", "C");
  }

  @Test @SuppressWarnings("unchecked")
  public void it_shouldStartAllObservables() {
    TestObservable<String> letters = TestObservable.createTestObservable("A", "B", "C");
    TestObservable<String> numbers = TestObservable.createDelayedTestObservable(100, "1", "2", "3");
    TestObservable<String> animals = TestObservable.createDelayedTestObservable(200, "zebra", "donkey", "unicorn");

    Observable<String> observable = ConcatObservable.from(letters, numbers, animals).asObservable();

    TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
    observable.subscribe(testSubscriber);

    assertThat(letters.isCalled()).isTrue();
    assertThat(numbers.isCalled()).isTrue();
    assertThat(animals.isCalled()).isTrue();
  }

  static class TestObservable<T> extends Observable<T> {
    private final TestOnSubscribe<T> onSubscribeFunc;

    private TestObservable(TestOnSubscribe<T> f) {
      super(f);
      onSubscribeFunc = f;
    }

    public boolean isCalled() {
      return onSubscribeFunc.isCalled();
    }

    @SuppressWarnings("unchecked")
    public static <T> TestObservable<T> createTestObservable(final T... items) {
      return createDelayedTestObservable(0, items);
    }

    @SuppressWarnings("unchecked")
    public static <T> TestObservable<T> createDelayedTestObservable(final long delay, final T... items) {
      return new TestObservable<T>(new TestOnSubscribe<T>(delay, items));
    }

    private static class TestOnSubscribe<T> implements OnSubscribe<T> {
      private final long delay;
      private final T[] items;
      private boolean isCalled;

      private TestOnSubscribe(long delay, T... items) {
        this.delay = delay;
        this.items = items;
      }

      @Override public void call(Subscriber<? super T> subscriber) {
        isCalled = true;

        for (T item : items) {
          if (delay > 0) {
            sleep(delay);
          }
          subscriber.onNext(item);
        }
        subscriber.onCompleted();
      }

      public boolean isCalled() {
        return isCalled;
      }

      private void sleep(long time) {
        try {
          Thread.sleep(time);
        } catch (InterruptedException e) { }
      }
    }
  }
}

你能在下面核对我的答案吗?我对它进行了单元测试,似乎工作正常。你能用你的单元测试来测试这个新答案吗?我认为这不能满足我的需要。当我说如果A,B,或C发射任何东西,不发射任何其他东西,我的意思是只发射那个可观测的东西,而不发射其他东西。我不是说发出一个项目。我用一个失败的测试编辑了你的答案,以显示我正在寻找的行为。很抱歉回复太晚。ReplaySubject是个聪明的主意。刚刚在代码中发现一个问题:您没有正确设置订阅。请看我的最新答案。你能告诉我他们怎么不正确吗?我的测试都表明这是工作良好。我已经在我的答案中添加了我的测试。我的意思是,即使输入列表更准确,用户也可能希望在任何列表之前取消订阅