【问题标题】:RxJava 2 - Call Completable after another CompletableRxJava 2 - 在另一个 Completable 之后调用 Completable
【发布时间】:2020-03-01 18:53:34
【问题描述】:

我是 RxJava 的新手,遇到如下问题:

我有两个 Completable 对象来存储一些数据。我想触发第一个,然后在第一个成功完成后才开始第二个。对第二个 Completable 的调用应该被阻止,直到第一个 Completable 成功完成。另外,如果第一个错误结束,另一个也应该跳过。

查看文档和其他 SO 问题,concatWithandThen 似乎对我有用。但是在手动测试和单元测试中,我可以看到第二个可完成项与第一个可完成项并行触发:/

第一个可完成的

public Completable doA() {
  Log.d(TAG, "class call");

  return db.countRows()
    .doOnSuccess(integer -> {
      Log.d(TAG, "found rows: "+integer);
    })
    .doOnError(Throwable::printStackTrace)
    .flatMapCompletable(this::customAction);
}

private Completable customAction(final int count) {
  Log.d(TAG, "count: "+count);
  if (count > 0) {
    Log.d(TAG, "no rows, skip");
    return Completable.complete();
  }

  final User user = ...
  return db.save(user); // return Completable
}

第二个可完成的

public Completable doB() {
  Log.d(TAG, "call to B");
  // ...
}

尝试在 A 之后调用 B

public Completable someMethod() {
    Log.d(TAG, "someMethod");
    return doA()
        .andThen(doB());
        // this also doesn't work
        //.concatWith(doB());
}

订阅

someMethod()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .doOnComplete(() -> {
      Log.d(TAG, "complete");
      // ...
    })
    .doOnError(throwable -> {
      Log.d("Main", "error "+throwable.getMessage());
      // ...
    })
    .subscribe();

当我运行我的应用并检查日志时,我可以看到:

D/Some method: some method
D/DoA: class call
D/DoB: class call   // <- why here?
D/DoA: found rows: 0
D/DoA: count: 0

以下单元测试也失败了:

@Test
public void test() {
  when(doa.doA()).thenReturn(Completable.error(new Exception("test")));

  observe(); // subscription with TestObserver

  verify(dob, never()).doB(); // fails with NeverWantedButInvoked
}

我错过了什么?

【问题讨论】:

  • 您能否分享一下您是如何重写此代码的,以便能够验证 .andThen(...) 直到第一个可完成之后才“发生”?

标签: java rx-android rx-java2


【解决方案1】:

因为你打电话给doB()。让我重写你的流程:

public Completable someMethod() {
    Log.d(TAG, "someMethod");

    // doA() inlined
    LOG.d("class call");
    Completable a = ...

    // doB() inlined
    Log.d("class call");
    Completable b = ...

    return a.andThen(b);
}

【讨论】:

  • 我看不出我的和你的 sn-p 之间的差异可能会影响可完成项的顺序。你能再解释一下吗?
  • 您认为它们是并行运行的,但实际上您在两个class calls 实际执行之前按顺序记录它们。
  • 是的,经过进一步调查,我也意识到了这一点。调用部分代码(包括日志)是因为它们不是 Completable 主体的一部分。感谢您的提示!
  • 并行执行多个 Completable 怎么样?
  • 我不太喜欢这样的频道,因为它们不利于就特定问题进行有限的对话。 slack 也是半私有的,StackOverflow 至少允许其他人发现他们面临的类似问题的答案。
【解决方案2】:

您可以使用 andThen()concatWith() 运算符。

返回一个 Completable,它首先运行这个 Completable,然后运行另一个 Completable。

andThen()

firstCompletable
    .andThen(secondCompletable)

一般来说,这个操作符是 Completable 上 flatMap 的“替代品”:

Completable       andThen(CompletableSource next)
<T> Maybe<T>      andThen(MaybeSource<T> next)
<T> Observable<T> andThen(ObservableSource<T> next)
<T> Flowable<T>   andThen(Publisher<T> next)
<T> Single<T>     andThen(SingleSource<T> next)

concatWith

firstCompletable
        .concatWith(secondCompletable)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多