RxJava:当流之一不发出任何信号时,如何处理combinateLatest()

时间:2018-07-06 20:13:21

标签: java android rx-java rx-java2 rx-android

我使用combinateLatest()来组合3个可观察值流。将所有这些组合在一起,以便同时显示UI中的所有数据。现在,存在一种情况,其中可观察对象之一将不会发出任何东西,因为获取的数据可能为空。

是否有RxJava运算符让订户知道由于空数据而不会产生任何发射?

修改

private fun retrieveData() {
    Observable.combineLatest(getCurrentUser.execute(), getLatestGoal.execute(), getLatestLog.execute(),
            Function3<User, Goal, Log, PersonalViewModel> { user, goal, log -> mapToViewModel(user, goal, log) })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnSubscribe { /*todo: animation*/ }
            .doOnNext { view.setViewModel(it) }
            .doOnComplete { view.stopLoading() }
            .doOnError { /*todo: error message*/ }
            .subscribe()
}

第三个流:当用户拥有nog日志时,getLatestLog.execute()不发出任何内容。当此流不发出时,整个视图将不可见。

从FireBase Realtime数据库中获取数据。 ChildEventListener具有如下所示的方法:

override fun onChildAdded(dataSnapshot: DataSnapshot?, p1: String?) {
                val log = dataSnapshot?.getValue(Log::class.java)
                log?.let { subscriber.onNext(it) }
                subscriber.onComplete()
                firebaseDatabase.reference.removeEventListener(this)
            }

2 个答案:

答案 0 :(得分:1)

如果您可以轻松使用Java8或某些Optional,则可以使用以下结构:

  @Test
  void name() {
    TestScheduler scheduler = new TestScheduler();

    Observable<Optional<Integer>> o1$ =
        Observable.just(Optional.ofNullable(4)).mergeWith(Observable.never());
    Observable<Optional<Integer>> o2$ =
        Observable.just(Optional.ofNullable(2)).mergeWith(Observable.never());

    Observable<Optional<Integer>> o3$ =
        Observable.<Optional<Integer>>never()
            .timeout(1000, TimeUnit.MILLISECONDS, scheduler)
            .onErrorResumeNext(
                throwable -> {
                  return Observable.<Optional<Integer>>never()
                      .mergeWith(Observable.just(Optional.empty()));
                });

    Observable<Tuple3<Optional<Integer>, Optional<Integer>, Optional<Integer>>> result =
        Observable.combineLatest(
                o1$,
                o2$,
                o3$,
                (integer, integer2, integer3) -> Tuple.of(integer, integer2, integer3))
            .filter(t -> t._1.isPresent() && t._2.isPresent() && t._3.isPresent());

    TestObserver<Tuple3<Optional<Integer>, Optional<Integer>, Optional<Integer>>> test =
        result.test();

    scheduler.advanceTimeTo(10000, TimeUnit.SECONDS);

    test.assertNotComplete().assertNoErrors().assertNoValues();
  }

您可能没有,不允许通过observables-pipeline发出null值。因此,我们需要其他一些构造来表示null。在Java8中,有一个名为Optional的结构(vavr称其为Option-> Java8)。

在此示例中,o3 $ -Observable将不会发出任何东西。也可能会出错,也许这与您的情况有点相似。我们将捕获错误(在这种情况下为timeout-exception),并返回带有Optional.empty的Observable。

在组合回调中,我们组合所有三个值。在随后的步骤中,我们将筛选出所有具有有效值(带值的可选值)的元组。

只有在所有三个值都发出一个值后,您才会发出一个值。

当您不能使用Optional-class时,也可以像下面的示例一样定义INVALID-Object:

class So51217041 {
  private static Integer INVALID_VALUE = 42;

  @Test
  void name() {
    Observable<Integer> o1$ = Observable.just(4).mergeWith(Observable.never());
    Observable<Integer> o2$ = Observable.just(2).mergeWith(Observable.never());

    Observable<Integer> o3$ =
        Observable.<Integer>never()
            .onErrorResumeNext(
                throwable -> {
                  return Observable.<Integer>never().mergeWith(Observable.just(INVALID_VALUE));
                });

    Observable<Tuple3<Integer, Integer, Integer>> result =
        Observable.combineLatest(
                o1$,
                o2$,
                o3$,
                (integer, integer2, integer3) -> Tuple.of(integer, integer2, integer3))
            .filter(t -> t._3 != INVALID_VALUE); // yeah I know, I want to compare reference, not the content

    TestObserver<Tuple3<Integer, Integer, Integer>> test = result.test();

    test.assertNotComplete().assertNoErrors().assertNoValues();
  }
}

此外,当您希望流以INVALID或NULL开头时,CombineLatest发出至少一个值,则可以使用Observable#startWith(INVALID)或Observable#startWith(Optional.empty())。这将确保可观察对象至少发出一个值。

答案 1 :(得分:1)

您可以使用public final Single first(T defaultItem)方法。所以代码看起来像这样

getLatestLog.execute()
.first(someDefaultNonNullLog)
.toObservable()