如何使用一个可观察对象的状态来跳过另一个可观察对象的值



用一个简短的例子来说明这一点。
假设这是我要过滤的源可观察对象

Observable.interval(1, TimeUnit.SECONDS)

我使用一个复选框来处理过滤器状态。当框未选中时,我想跳过所有值。
我使用RxAndroid获得一个可观察的复选框,像这样:

RxCompoundButton.checkedChanges(checkBox)
下面是我的代码:
    Observable.combineLatest(
            RxCompoundButton.checkedChanges(checkBox)
            , Observable.interval(1, TimeUnit.SECONDS)
            , (isChecked, intervalCounter) -> {
                if (!isChecked) {
                    return null;
                } else {
                    return intervalCounter;
                }
            }
    ).filter(Objects::nonNull)
我得到了想要的输出
interval       1--2--3--4--5--6--7--8--9  
checkbox       0-----1--------0-----1---
combineLatest
result         ------3--4--5--------8--9

我刚刚开始使用RxJava,我的"解决方案"感觉不太对,因为:
您可以看到,combine函数返回一个魔术值null,然后过滤器将跳过这些nulls
这意味着即使我已经知道我想跳过这个数据,也会调用过滤器函数。

  • 也许我应该用另一个操作符
  • 是否有办法在过滤器函数
  • 中使用可观察的复选框?
  • 可能在combine函数中有某种方式表示我想跳过这个数据

您对所需输出的图片不正确。在您的实现中,combineLatestnull合并到流中:

interval       1--2--3--4--5--6--7--8--9  
checkbox       0-----1--------0-----1---
combineLatest  N--N--3--4--5--N--N--8--9
filter(NonNull)------3--4--5--------8--9 

恕我直言,在Rx流中使用null作为信号并不好,开发人员很容易陷入NullPointerException

要避免使用null,有两个措施。第一个是将结果转换为Pair,并应用滤波器&地图。

一个非常简单的Pair类:
public class Pair<T, U> {
    T first;
    U second;
    public Pair(T first, U second) {
        this.first = first;
        this.second = second;
    }
}

那么整个实现是这样的:

Observable.combineLatest(
        RxCompoundButton.checkedChanges(checkBox)
        , Observable.interval(1, TimeUnit.SECONDS)
        , (isChecked, intervalCounter) -> new Pair<>(isChecked,intervalCounter)
).filter(pair -> pair.first)
 .map(pair -> pair.second)  // optional, do this if you only need the second part

数据流:

interval          1      2      3      4
                  |      |      |      |
checkbox        F |  T   |   F  |  T   F
                  |  |   |   |  |  |   |
combineLatest    F1  T1  T2  F2 F3 T3  F4
                     |   |         |
filter(first=T)      T1  T2        T3
                     |   |         | 
map(second)          1   2         3

或者如果你可以在你的项目中使用Java 8,使用Optional来避免null,这与你的解决方案非常相似,但它给其他开发人员意识到流信号是Optional

Observable<Optional<Integer>> o1 = Observable.combineLatest(
        RxCompoundButton.checkedChanges(checkBox)
        , Observable.interval(1, TimeUnit.SECONDS)
        , (isChecked, intervalCounter) -> {
            if (!isChecked) {
                return Optional.empty();
            } else {
                return Optional.of(intervalCounter);
            }
        }
)
Observable<Integer> o2 = o1.filter(Optional::isPresent).map(Optional::get)

一些更简单的方法,与combineLatest不同,但与您想要的结果图片相同。

// Approach 1
Observable.interval(1, TimeUnit.SECONDS).filter( i -> checkBox.isEnabled())
// Approach 2
Observable.interval(1, TimeUnit.SECONDS)
  .withLatestFrom(
    RxCompoundButton.checkedChanges(checkBox),
    (isChecked, intervalCounter) -> {
            if (!isChecked) {
                return Optional.empty();
            } else {
                return Optional.of(intervalCounter);
            }
     }).filter(Optional::isPresent).map(Optional::get)

相关内容

  • 没有找到相关文章

最新更新