簡體   English   中英

RxJava:當其中一個流沒有發出任何內容時,如何處理combineLatest()

[英]RxJava: how to handle combineLatest() when one of the streams emits nothing

我使用combineLatest()來組合3個可觀察流。 所有這些組合在一起,以便UI中的所有數據同時顯示。 現在,有一種情況是其中一個observable不會發出任何內容,因為獲取的數據可以為null。

是否有一個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()
}

第三個流:getLatestLog.execute()在用戶具有nog日志時不發出任何內容。 當此流未發出時,整個視圖將不可見。

數據從FireBase實時數據庫中獲取。 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)
            }

如果你手上有Java8或一些Optionals,你可以使用這個結構:

  @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。 在Java8中有一個名為Optional的構造(vavr稱之為Option - >也是Java8)。

在這個例子中,o3 $ -Observable不會發出任何東西。 它也可能是錯誤的,也許這類似於你的情況。 我們將捕獲錯誤(在這種情況下:timeout-exception)並返回帶有Optional.empty的Observable。

在組合回調中,我們將三個值組合起來。 在后面的步驟中,我們過濾掉所有元組,它們都具有有效值(Optional with Value)。

只有在使用值發出所有三個值時,才會獲得一個值。

如果不能使用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())。 這將保證,observable至少會發出一個值。

您可以使用public final Single first(T defaultItem)方法。 所以代碼可能看起來像這樣

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM