如何使用一个observable的状态来跳过另一个observable的值?

时间:2016-10-15 12:03:31

标签: java rx-java rx-android

最好用一个简短的例子来解释 让我们说这是我的源可观察,我想过滤

<table>
  <tr>
    <td id="rk1">First RK</td>
    <td id="rk1_1">09231</td>
  </tr>
  <tr>
    <td id="rk2">Second RK</td>
    <td id="rk2_1">60234</td>
    <td id="rk2_2">69260</td>
  </tr>
  <tr>
    <td id="rk3">Third RK</td>
    <td id="rk3_1">30224</td>
    <td id="rk3_2">30302</td>
    <td id="rk3_3">20280</td>
    <td id="rk3_4">82122</td>
  </tr>
</table>

我使用复选框来处理过滤器状态。如果未选中此框,我想跳过所有值 我使用RxAndroid来获取这样的复选框的可观察性:

Observable.interval(1, TimeUnit.SECONDS)

这是我的代码:

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)

我刚开始使用RxJava并且我的“解决方案”感觉不对,因为:
你可以看到combine函数返回一个魔术值interval 1--2--3--4--5--6--7--8--9 checkbox 0-----1--------0-----1--- combineLatest result ------3--4--5--------8--9 ,然后过滤器会跳过这些null
这意味着即使我已经知道,我也想要过滤掉这个数据。

  • 也许我应该使用另一个运营商
  • 有没有办法在过滤函数中使用checkbox-observable
  • 也许在合并功能中有一些方法可以表示我想跳过这些数据

1 个答案:

答案 0 :(得分:3)

所需输出的图片不正确。在您的实施中,combineLatest正在将null合并到流中:

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 

恕我直言,使用null作为信号并不适合Rx Stream,开发人员很容易陷入NullPointerException

为避免使用null,有两项措施。第一个是将结果转换为一对,并应用过滤器和放大器。地图以后。

一个非常简单的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,这与您的解决方案非常相似,但它让其他开发人员意识到Stream信号为{{1} }}

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