Observable.just(doSomeLongStuff())在我订阅observable之前先运行doSomeLongStuff()

时间:2019-07-10 20:01:06

标签: java observable rx-java reactive-programming rx-java2

我对RxJava2有愚蠢的问题。

我需要同时运行两个长时间的操作。我知道我应该使用Observable.zip()并使用它。

问题是我的长操作是一个接一个地运行,另一个问题是我的长操作在我订阅它们之前就开始了。

让我们想象这是我应该异步运行的漫长操作。

private String doSomethingLong() {
        Random rand = new Random();
        int value = rand.nextInt(5);
        Timber.i("Do something for [%d] sec [%s]", value, Thread.currentThread().getName());
        try {
            Thread.sleep(value * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return String.format(Locale.getDefault(), "Exception [%s]", e.getMessage());
        }
        return String.format(Locale.getDefault(),"Job for [%d] seconds", value);
    }

还有一个类似test()的方法将尝试使其平行:

public void test() {

        final long started = System.currentTimeMillis();
        Observable<String> just1 = Observable.just(doSomethingLong()).subscribeOn(Schedulers.newThread());
        Observable<String> just2 = Observable.just(doSomethingLong()).subscribeOn(Schedulers.newThread());


        Observable.zip(just1, just2, new Func2<String, String, Combined>() {
            @Override
            public Combined call(String s, String s2) {
                return new Combined(s, s2);
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Combined>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Combined combined) {
                long total = System.currentTimeMillis() - started;
                Timber.i("TOTAL [%d]ms [%s]", total, combined.toString());
            }
        });

    }

当我尝试运行此命令时,我发现两个可观察变量just1和just2依次运行...这让我感到困惑...

但是还有另一位员工让我感到困惑...我评论了Observable.zip,并注意到在我订阅它们之前,just1和just2启动了方法doSomethingLong()...

让我展示:

public void test() {

        final long started = System.currentTimeMillis();
        Observable<String> just1 = Observable.just(doSomethingLong()).subscribeOn(Schedulers.newThread());
        Observable<String> just2 = Observable.just(doSomethingLong()).subscribeOn(Schedulers.newThread());


//        Observable.zip(just1, just2, new Func2<String, String, Combined>() {
//            @Override
//            public Combined call(String s, String s2) {
//                return new Combined(s, s2);
//            }
//        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<Combined>() {
//            @Override
//            public void onCompleted() {
//
//            }
//
//            @Override
//            public void onError(Throwable e) {
//
//            }
//
//            @Override
//            public void onNext(Combined combined) {
//                long total = System.currentTimeMillis() - started;
//                Timber.i("TOTAL [%d]ms [%s]", total, combined.toString());
//            }
//        });

    }

这段代码几乎相同-它一次执行两次doSomethingLong()...

我期望的是:  1.我需要doSomethingLong()方法并行运行  2.我要解释为什么这些方法在我开始订阅之前就运行。  3.在这种情况下,我应该如何编写代码。我希望在我订阅它们之前不调用doSomethingLong()方法。

非常感谢。希望我能很好地解释问题。

2 个答案:

答案 0 :(得分:3)

订阅时

Observable.just不会运行任何内容。当您订阅时,它会发出元素,但是您将doSomethingLong作为参数传递后将立即运行。那是正常的,这就是语言的工作方式。

您正在寻找的是一种在我们订阅时说返回此内容的方法,但也只能在那个时候运行它,并希望在后台线程上运行它。

有两个答案,这是一些

使用延迟

有一个名为defer的运算符,它接受一个lambda,一旦您订阅,该lambda将被执行:

Observable.defer(() ->  doSomethingLong())

这只会在您订阅时执行doSomethingLong

使用fromCallable

您可以从lambda创建一个可观察对象。这称为fromCallable

Observable.fromCallable(() -> doSomethingLong())

类似地,这仅在您订阅时运行doSomethingLong

使用创建

我认为这可能是最不鼓励这样做的方式,因为您需要处理很多事情,但是对于完整的她,我可以提一下:

Observable.create( emitter -> {
    if(emitter.isDisposed()) return;

    emitter.onNext(doSomethingLong());
    emitter.onComplete();
});

同样,我敢肯定还有更多的方法可以做到这一点。我只是想解释这个问题,并提供一些选择。

答案 1 :(得分:0)

将您的Observable创建为Observable.fromCallable {}。 而不是zip,请使用CombineLatest()

文档: http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html#fromCallable-java.util.concurrent.Callable- http://reactivex.io/documentation/operators/combinelatest.html