如何使用一个 observable 的状态来跳过另一个 observable 的值? [英] How to use the state of one observable to skip values of another observable?

查看:45
本文介绍了如何使用一个 observable 的状态来跳过另一个 observable 的值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最好用一个简短的例子来解释.
假设这是我要过滤的源 observable

This is best explained with a short example.
let's say this is my source observable that I want to filter

Observable.interval(1, TimeUnit.SECONDS)

我使用复选框来处理过滤器状态.未选中该框时,我想跳过所有值.
我使用 RxAndroid 来获取复选框的 observable,如下所示:

I use a checkbox to handle the filter state. When the box is not checked, I want to skip all values.
I use RxAndroid to get an observable for the checkbox like this:

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,我的解决方案"感觉不对,因为:
您可以看到组合函数返回一个幻值null,然后过滤器将跳过这些nulls.
这意味着即使我已经知道要跳过这些数据,也会调用过滤器函数.

I am just getting started with RxJava and my "solution" does not feel right, because:
You can see that the combine function returns a magic value null and then the filter will skip these nulls.
That means that the filter function is called even though I already know, that I want to skip this data.

  • 也许我应该使用另一个运算符
  • 有没有办法在过滤器函数中使用 checkbox-observable
  • 也许在组合函数中有某种方式来表示我想跳过这些数据

推荐答案

您想要输出的图片不正确.在您的实现中,combineLatestnull 组合到流中:

Your pictures of the desired output is not correct. In your implementation combineLatest is combining a null into the stream :

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 Stream中使用null作为信号不好,开发者很容易陷入NullPointerException.

IMHO, using null as a signal is not good in Rx Stream, developers can easily fall into NullPointerException.

为了避免使用null,有两个措施.第一个是将结果转换为 Pair,并应用 filter &稍后映射.

To avoid the use of null, there are two measures. The first one is to transform the result to a Pair, and apply filter & map later.

一个非常简单的Pair类:

public class Pair<T, U> {
    T first;
    U second;

    public Pair(T first, U second) {
        this.first = first;
        this.second = second;
    }
}

那么整个实现应该是这样的:

Then the whole implementation would like this:

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,这与您的解决方案非常相似,但它让其他开发人员意识到流信号是可选的.

Or if you can Java 8 in your project, use Optional to avoid null, which is very similar to your solution but it gives the awareness for others developers that the Stream signal is 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 不同,但与您想要的结果图片相同.

Some easier approach which is not same with combineLatest but identical to your desired result pictures.

// 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)

这篇关于如何使用一个 observable 的状态来跳过另一个 observable 的值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆