2016-10-15 42 views
1

这可以用一个简短的例子来解释。
让我们说这是我观察到的来源,我想筛选如何使用一个observable的状态来跳过另一个observable的值?

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和我的“解决方案”感觉不对,因为:
您可以看到组合乐趣ction返回一个魔术值null,然后过滤器将跳过这些nulls
这意味着即使我已经知道,我要跳过此数据,但仍然调用过滤器函数。

  • 也许我应该使用其他运营商
  • 有使用复选框,观察到在过滤器功能的方式
  • 也许有一些办法的组合函数信号,我想跳过这个数据

回答

2

您所需输出的图片不正确。在您的实现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 

恕我直言,使用null作为信号不是处于RX流良好,开发人员可以很容易陷入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,这是与您的解决方案非常相似,但它为其他开发人员提供了Stream信号为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) 
相关问题