在RxJava2中,如果值相等,如何比较和过滤两个可观察对象?

时间:2019-03-21 16:24:30

标签: rx-java2

我是RxJava2的新手。

我正在尝试从缓存和服务器获取事务对象的列表。 我想将服务器值与缓存值进行比较,如果服务器值相同,则将其忽略。

我能够使用.scan()轻松地完成此操作,因为我们可以返回null,而当从.scan()返回null时,该值将被忽略(过滤)。

RxJava 1

private Observable<List<Transaction>> getTransactionsFromCacheAndServer() {
    return Observable.concat(
            getTransactionsFromCache(),
            getTransactionsFromServer()
    )
            .scan((p1, p2) -> {
                if (p1 == null && p2 != null) {
                    return p2;
                } else if (p1 != null && !isListSame(p1, p2)) {
                    return p2;
                } else {
                    return null;
                }
            });
}

使用RxJava 2,由于我再也无法返回null,所以事情变得不容易。

RxJava 2

    private Observable<List<Transaction>> getTransactionsFromCacheAndServer() {
    return Observable.concat(
            getTransactionsFromCache(),
            getTransactionsFromServer()
    )
            .map(FilterObject::new)
            .scan((filterObject1, filterObject2) -> {
                List<Transaction> p1 = (List<Transaction>)filterObject1.value;
                List<Transaction> p2 = (List<Transaction>)filterObject2.value;

                if (p1.size() == 0 && p2.size() > 0) {
                    return filterObject2;
                } else if (!isListSame(p1, p2)) {
                    return filterObject2;
                } else {
                    filterObject2.filter = true;
                    return filterObject2;
                }
            })
            .filter(filterObject -> !filterObject.filter)
            .map(filterObject -> (List<Transaction>)filterObject.value);
}

其中FilterObject是:

public class FilterObject {
public Object value;
public boolean filter;

public FilterObject(Object value) {
    this.value = value;
}

}

即使使用上述方法也可以实现相同的目的,但看起来却很丑陋。另外,我还必须包括两个性能可能不太友好的地图。

是否有简单/干净的方法来实现我想要的?

2 个答案:

答案 0 :(得分:2)

我认为没有通用的解决方案,因为一个空列表和一个需要过滤的列表(在所有情况下碰巧都是空的)是两种不同的东西(扫描的输出)并且需要以不同的方式处理。

但是,在您的特定情况下,您从不发出空列表,除了可能用于第一个输出。

(我使用String代替Transaction,没关系)

private Observable<List<String>> getTransactionsFromCacheAndServer() {
    return Observable.concat(
            getTransactionsFromCache(),
            getTransactionsFromServer()
    )
            .filter(list -> !list.isEmpty())
            // If you prefer a consistent empty list over the first
            // empty list emission getting filtered
            .startWith((List<String>) Collections.EMPTY_LIST)
            // Newly emitted value cannot be empty, it only depends only on the comparison
            .distinctUntilChanged(this::isListSame);
}

这是我用最少的运算符可以获得的最接近的结果。希望它能解决您的问题。

答案 1 :(得分:1)

基于andras' answer,我做了一些修改以实现我想要的。

private Observable<List<String>> getTransactionsFromCacheAndServer() {
    return Observable.concat(
        getTransactionsFromCache(),
        getTransactionsFromServer()
    )
        .filter(list -> !list.isEmpty())
        .distinctUntilChanged(this::isListSame)
        .switchIfEmpty(Observable.just(new ArrayList<>()));

}

安德烈亚斯(Andreas)的答案将始终收到一个空列表,然后是真实数据。

我上面的解决方案将收到:
1.缓存中的数据(如果不同则从服务器中获取数据)
2.如果缓存和服务器均返回“空列表”,则为空列表。