根据条件从列表中创建Observable

时间:2017-02-08 11:44:47

标签: android rx-java

我是RxJava的新手,所以我在努力做这类事情,事情是

我有一个Observable从另一个名为Gatekeeper的类发出List映射,如下所示:

        List<ParkappGate> actualgates = Observable.just(gates).concatMap(new Func1<List<Gatekeeper>, Observable<? extends List<ParkappGate>>>() {
        @Override
        public Observable<? extends List<ParkappGate>> call(List<Gatekeeper> gatekeepers) {
            final List<ParkappGate> gates = new ArrayList<ParkappGate>();
            for (Gatekeeper gate :
                    gatekeepers) {
                mDataManager.getGateById(gate.getCode()).subscribe(new Subscriber<ParkappGate>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(ParkappGate gate) {
                        gates.add(gate);
                    }
                });
            }
            return Observable.just(gates);
        }
    });

这个工作正常,所以现在我想创建一个Observable,它只发出一些条件下列表中有效的第一个项目,我在这里创建的是这样的:

  Observable<ParkappGate>   nearestValidGate = actualgates.
            concatMap(new Func1<List<ParkappGate>, Observable<? extends ParkappGate>>() {
                          @Override
                          public Observable<? extends ParkappGate> call(List<ParkappGate> parkappGates) {
                              for (ParkappGate gate :
                                      parkappGates) {
                                  if (isValidGate(gate))
                                      return Observable.just(gate);
                              }
                              return null;
                          }
                      }

我的问题在于,在验证ParkappGate时,我必须调用我创建的一个返回Observable<ParkappParking>的方法,另一个返回一个Observable并使用ParkappGate作为参数进行评估,然后返回如果方法isValidGate(ParkappGate gate)

的所有条件都是真的

我看到的一个简单方法是使用Observable<ParkappParking>Observable<Boolean>toBlocking.first()转换为值,但这似乎不是Reactive X的正确方法,所以我想知道怎么做得对。

3 个答案:

答案 0 :(得分:2)

所以你的问题是你的验证函数基本上是一个Observable?太糟糕的过滤器不能接受observable作为谓词。您可以对验证函数进行平面映射,但这样做会丢失对评估验证函数的对象的引用。但是,您可以使用临时对象来存储对象和验证函数的结果,然后对结果属性进行过滤。

这是它的外观。几个人注意到了;

  • 首先,我用基础操作符map,flatmap和filter重写了你的代码以简化它。

  • 其次,我使用了Observable,但你可以通过使用Single for isValidGate(...)和Maybe for nearestValidGate(...)来获得更具表现力的函数签名。

  • 最后,我使用了Rx 2但是使用Rx 1它应该主要是相同的。

Java pre-8中的代码:

package io.nemo.commons;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;

import static java.lang.Boolean.TRUE;

public class ParkSO {

    class Gatekeeper {
        public int getCode() {
            return 1; // Dump implementation
        }
    }

    class ParkappGate {

    }

    class ParkappParking {

    }

    class DataManager {
        public Observable<ParkappGate> getGateById(int code) {
            return Observable.just(new ParkappGate()); // Dumb implementation
        }
    }

    class GateKeeperValidation {
        private ParkappGate gate;
        private Boolean validation;

        public ParkappGate getGate() {
            return gate;
        }

        public Boolean getValidation() {
            return validation;
        }

        public GateKeeperValidation(ParkappGate gate, Boolean validation) {
            this.gate = gate;
            this.validation = validation;
        }
    }

    Observable<ParkappParking> getParking(ParkappGate gate) {
        return Observable.just(new ParkappParking()); // Dumb implementation
    }

    Observable<Boolean> isValidParking(ParkappParking parking) {
        return Observable.just(TRUE); // Dumb implementation
    }

    Observable<Boolean> isValidGate(ParkappGate gate) {
        return getParking(gate)
                .flatMap(new Function<ParkappParking, ObservableSource<Boolean>>() {
                    @Override
                    public ObservableSource<Boolean> apply(ParkappParking parkappParking) throws Exception {
                        return isValidParking(parkappParking);
                    }
                });
    }

    void main() {
        final DataManager mDataManager = new DataManager();
        final List<Gatekeeper> gateKeepers = new ArrayList<>();

        Observable.fromIterable(gateKeepers)
                .flatMap(new Function<Gatekeeper, ObservableSource<ParkappGate>>() {
                    @Override
                    public ObservableSource<ParkappGate> apply(Gatekeeper gatekeeper) throws Exception {
                        return mDataManager.getGateById(gatekeeper.getCode());
                    }
                })
                .flatMap(new Function<ParkappGate, ObservableSource<GateKeeperValidation>>() {
                    @Override
                    public ObservableSource<GateKeeperValidation> apply(final ParkappGate parkappGate) throws Exception {
                        return isValidGate(parkappGate)
                                .map(new Function<Boolean, GateKeeperValidation>() {
                            @Override
                            public GateKeeperValidation apply(Boolean validation) throws Exception {
                                return new GateKeeperValidation(parkappGate, validation);
                            }
                        });
                    }
                })
                .filter(new Predicate<GateKeeperValidation>() {
                    @Override
                    public boolean test(GateKeeperValidation gateKeeperValidation) throws Exception {
                        return gateKeeperValidation.getValidation();
                    }
                })
                .firstElement();
    }
}

使用Java 8的版本:

package io.nemo.commons;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;

import static java.lang.Boolean.TRUE;

public class ParkSOJava8 {

    class Gatekeeper {
        public int getCode() {
            return 1; // Dump implementation
        }
    }

    class ParkappGate {

    }

    class ParkappParking {

    }

    class DataManager {
        public Observable<ParkappGate> getGateById(int code) {
            return Observable.just(new ParkappGate()); // Dumb implementation
        }
    }

    class GateKeeperValidation {
        private ParkappGate gate;
        private Boolean validation;

        public ParkappGate getGate() {
            return gate;
        }

        public Boolean getValidation() {
            return validation;
        }

        public GateKeeperValidation(ParkappGate gate, Boolean validation) {
            this.gate = gate;
            this.validation = validation;
        }
    }

    Observable<ParkappParking> getParking(ParkappGate gate) {
        return Observable.just(new ParkappParking()); // Dumb implementation
    }

    Observable<Boolean> isValidParking(ParkappParking parking) {
        return Observable.just(TRUE); // Dumb implementation
    }

    Observable<GateKeeperValidation> isValidGate(ParkappGate gate) {
        return getParking(gate)
                .flatMap(this::isValidParking)
                .map(validation -> new GateKeeperValidation(gate, validation));
    }

    void main() {
        final DataManager mDataManager = new DataManager();
        final List<Gatekeeper> gateKeepers = new ArrayList<>();

        Observable.fromIterable(gateKeepers)
                .map(Gatekeeper::getCode)
                .flatMap(mDataManager::getGateById)
                .flatMap(this::isValidGate)
                .filter(GateKeeperValidation::getValidation)
                .firstElement();
    }
}

您也可以编写自己的filterWithObservable或filterWithSingle运算符。

答案 1 :(得分:1)

首先,你的第一种方法可以更加简洁地写成:

filter

请注意,如果您认为所有Observable都是等效迭代器,则可能不需要toList()。

要过滤掉无效的大门,只需使用 .filter(gate -> isValidGate(gate)) .first() 运算符:

{{1}}

请参阅?如果你不混合集合和Observables,一切都会更容易。

答案 2 :(得分:1)

  

我想创建一个仅发出第一个项目的Observable   有效

要根据您的要求发出与给定谓词匹配的第一个项目,您可以使用带有谓词{{​​3}}或first的运算符firstOrDefault和默认值谓词first(Func1<? super T, Boolean> predicate)

在你的情况下,它可能是这样的:

...
.first(this::isValidGate);