RxJava链接调用,有条件地结束和撤回第一个调用

时间:2016-06-03 13:52:24

标签: rx-java

我需要有关如何使用RxJava完成以下操作的建议。 我需要进行一系列链式调用,如果任何调用具有包含特定值的响应,则后续调用不得发生,并且必须返回该调用的值。

我正在尝试这样的事情:

public Observable<ReturnObject> doChainedApiCall() {
    Observable<ReturnObject> obs = service.apiCall1()
        .flatMap({
            if (call1Response.hasValue) {
                // don't do anymore api calls, return this
                ReturnObject obj = new ReturnObject();
                obj.setSomething();
                return Observable.just(obj);
            }
            return service.apiCall2();
        })
        .flatMap({
            if (call2Response.hasValue) {
                // don't do anymore api calls, return this
                ReturnObject obj = new ReturnObject();
                obj.setSomething();
                return Observable.just(obj);
            }
            return service.apiCall3();
        })
        .flatMap({
            ReturnObject obj = new ReturnObject();
            return Observable.just(obj);
        });

     return obs;
}

这段代码不会编译,只是对我想做的事情有所了解。

如何确保链在第一次调用时结束并在其中的检查为真时返回值?

3 个答案:

答案 0 :(得分:2)

我找到了自己问题的答案。

Observable<ReturnObject> observable = Observable.concat(
    apiCall1(),
    apiCall2(),
    apiCall3()
).flatMap(response -> {
    if (response.value == whatWeAreLookingFor) {
        ReturnObject obj = new ReturnObject();
        // set obj properties and return it.
        return Observable.just(obj);
    }
    // Return empty to continue with next call from .concat() list.
    return null; // or return Observable.empty();
}).first(); // Makes sure only the first non-empty result is called and returned.

.first()甚至可以替换为.firstOrDefault(Something),以确保最终返回的内容,如果3个api调用都没有我们正在寻找的内容。

感谢其他建议。我认为这种方式最简单,如果你知道一种更简单的方法,我很想知道。

答案 1 :(得分:1)

交换机是正确的轨道,但您必须编写自己的自定义运算符,如果条件满足则会切换,因为没有现有的条件。我从rxjava github存储库修改了OperatorSwitchIfEmpty运算符来执行此操作

import rx.*;
import rx.functions.Func1;
import rx.internal.producers.ProducerArbiter;
import rx.subscriptions.SerialSubscription;


public final class OperatorSwitchIfMatch<T> implements Observable.Operator<T, T> {
    private final Observable<? extends T> alternate;
    private final Func1<T, Boolean> selector ;
    public OperatorSwitchIfMatch(Observable<? extends T> alternate, Func1<T, Boolean> selector) {
        this.alternate = alternate;
        this.selector  = selector;
    }

    @Override
    public Subscriber<? super T> call(Subscriber<? super T> child) {
        final SerialSubscription ssub = new SerialSubscription();
        ProducerArbiter arbiter = new ProducerArbiter();
        final ParentSubscriber<T> parent = new ParentSubscriber<T>(child, ssub, arbiter, alternate,selector);
        ssub.set(parent);
        child.add(ssub);
        child.setProducer(arbiter);
        return parent;
    }

    private static final class ParentSubscriber<T> extends Subscriber<T> {

        private boolean matched = true;
        private final Subscriber<? super T> child;
        private final SerialSubscription ssub;
        private final ProducerArbiter arbiter;
        private final Observable<? extends T> alternate;
        private final Func1<T, Boolean> selector ;

        ParentSubscriber(Subscriber<? super T> child, final SerialSubscription ssub, ProducerArbiter arbiter, Observable<? extends T> alternate, Func1<T, Boolean> selector) {
            this.child = child;
            this.ssub = ssub;
            this.arbiter = arbiter;
            this.alternate = alternate;
            this.selector = selector;
        }

        @Override
        public void setProducer(final Producer producer) {
            arbiter.setProducer(producer);
        }

        @Override
        public void onCompleted() {            
                child.onCompleted();
        }

        private void subscribeToAlternate() {
            AlternateSubscriber<T> as = new AlternateSubscriber<T>(child, arbiter);
            ssub.set(as);
            alternate.unsafeSubscribe(as);
        }

        @Override
        public void onError(Throwable e) {
            child.onError(e);
        }

        @Override
        public void onNext(T t) {
            if (selector.call(t)) {
                if (!child.isUnsubscribed()) {
                    subscribeToAlternate();
                }
            } else {
                child.onNext(t);
            }
            arbiter.produced(1);
        }
    }

    private static final class AlternateSubscriber<T> extends Subscriber<T> {

        private final ProducerArbiter arbiter;
        private final Subscriber<? super T> child;

        AlternateSubscriber(Subscriber<? super T> child, ProducerArbiter arbiter) {
            this.child = child;
            this.arbiter = arbiter;
        }

        @Override
        public void setProducer(final Producer producer) {
            arbiter.setProducer(producer);
        }

        @Override
        public void onCompleted() {
            child.onCompleted();
        }

        @Override
        public void onError(Throwable e) {
            child.onError(e);
        }

        @Override
        public void onNext(T t) {
            child.onNext(t);
            arbiter.produced(1);
        }        
    }
}

然后您可以像

一样使用它
import rx.Observable;

public class SwitchMatchTest {


    public static void main(String[] args) throws InterruptedException {
        Observable<Integer> stream1 = Observable.just(9,1,1,1,1,9,1); // Will be skipped because it starts with 9
        Observable<Integer> stream2 = Observable.just(9,2,2,2,9,11); // Will be skipped because stream2 starts with 9
        Observable<Integer> stream3 = Observable.just(9,3,3,9,11);  
        Observable<Integer> stest = stream1.lift(new OperatorSwitchIfMatch<Integer>(stream2, x -> x>6)).lift(new OperatorSwitchIfMatch<Integer>(stream3, x -> x>6));

        stest.subscribe(l -> System.out.println("Emitted : " + l), e -> {}, () -> System.out.println("Completed"));
        Thread.sleep(2000L);
    }

}

在你的情况下,你会使用像

这样的东西
service.apiCall1().lift(new OperatorSwitchIfMatch<Response<AnObject>>(service.apiCall2(), x -> !x.hasValue))
                  .lift(new OperatorSwitchIfMatch<Response<AnObject>>(service.apiCall3(), x -> !x.hasValue))
                  .lift(new OperatorSwitchIfMatch<Response<AnObject>>(somedefaultObservable, x -> !x.hasValue))

答案 2 :(得分:0)

假设您的apiCallX方法都返回Observable,如果它们都在onCompleted事件中正确完成,您可以使用switchIfEmpty和/或{{1}运营商。像这样:

defaultIfEmpty

顺便说一下。 javadoc中列出了所有运算符(大多数包括大理石图)。