根据onSuccess()值重复一次

时间:2018-08-01 21:12:31

标签: rx-java2

我想基于Single中发出的单个值重复onSuccess()。这是一个有效的例子

import org.reactivestreams.Publisher;

import io.reactivex.Flowable;
import io.reactivex.Single;
import io.reactivex.functions.Function;

public class Temp {

    void main() {
        Job job = new Job();

        Single.just(job)
                .map(this::processJob)
                .repeatWhen(new Function<Flowable<Object>, Publisher<?>>() {
                    @Override
                    public Publisher<?> apply(Flowable<Object> objectFlowable) throws Exception {
                        // TODO repeat when Single emits false
                        return null;
                    }
                })
                .subscribe();
    }

    /**
     * returns true if process succeeded, false if failed
     */
    boolean processJob(Job job) {
        return true;
    }

    class Job {
    }
}

我通过依靠“完成”通知来了解repeatWhen对于Observable的工作方式。但是,由于Single没有收到该通知,所以我不确定Flowable<Object>到底给了我什么。还有为什么我需要从该函数返回Publisher

3 个答案:

答案 0 :(得分:1)

代替依赖布尔值,可以使作业失败时引发异常:

class Job {
    var isSuccess: Boolean = false
}

fun processJob(job: Job): String {
    if (job.isSuccess) {
        return "job succeeds"
    } else {
        throw Exception("job failed")
    }
}

val job = Job()
Single.just(job)
        .map { processJob(it) }
        .retry() // will resubscribe until your job succeeds
        .subscribe(
                { value -> print(value) },
                { error -> print(error) }
        )

答案 1 :(得分:0)

我在最新的docs和您的代码中发现了一个小差异,所以我做了一些挖掘工作……

(旁注-我认为retryWhen的语义似乎更适合您的情况,因此我用它代替了repeatWhen的用法。但是我认为无论哪种情况,您的问题都一样)。

retryWhen的签名是:

retryWhen(Function<? super Flowable<Throwable>,? extends Publisher<?>> handler)

该参数是工厂函数,其输入是随时onError发出的源,被称为上游,从而使您能够插入自定义重试逻辑,该逻辑可能会受到基础Throwable的询问而影响。这开始回答您的第一个问题:“我不确定Flowable<Object>到底给了我什么”-开头不应该是Flowable<Object>,应该是Flowable<Throwable>(由于我刚才描述的原因)。

那么Flowable<Object>是哪里来的?我通过使用RxJava版本2.1.17的自动完成功能设法重现了IntelliJ的代码生成。但是,升级到2.2.0会产生Flowable<Throwable>的正确结果。因此,请查看是否升级到最新版本也会为您生成正确的结果。

关于您的第二个问题:“为什么还要从此函数返回Publisher?” -这用于确定是否应该进行重新订阅。如果工厂函数返回一个发出终端状态的Publisher(即调用onError()onComplete()),则不会进行重新订阅。但是,如果调用onNext(),它将调用。 (这也解释了为什么不键入Publisher-类型无关紧要。唯一重要的是它发布的是哪种通知)。

结合上述内容的另一种重写方法可能如下:

// just some type to use as a signal to retry
private class SpecialException extends RuntimeException {}

// job processing results in a Completable that either completes or 
// doesn't (by way of an exception)
private Completable rxProcessJob(Job job) {
    return Completable.complete();
    // return Completable.error(new SpecialException());
}

...

rxProcessJob(new Job())
        .retryWhen(errors -> {
            return errors.flatMap(throwable -> {
                if(throwable instanceof SpecialException) {
                    return PublishProcessor.just(1);
                }

                return PublishProcessor.error(throwable);
            });
        })
        .subscribe(
                () -> {
                    System.out.println("## onComplete()");
                },
                error -> {
                    System.out.println("## onError(" + error.getMessage() + ")");
                }
        );

我希望有帮助!

答案 2 :(得分:0)

被接受的答案会起作用,但是有点黑。您无需抛出错误;只需过滤processJob的输出即可将Single转换为Maybe,然后使用repeatWhen处理程序来决定您想要多少次或延迟多少时间重新订阅。请从下面的示例中查看Kotlin代码,您应该可以轻松地将其转换为Java。

filter { it }
.repeatWhen { handler ->
    handler.zipWith(1..3) { _, i -> i }
        .flatMap { retryCount -> Flowable.timer(retryDelay.toDouble().pow(retryCount).toLong(), TimeUnit.SECONDS) }
        .doOnNext { log.warn("Retrying...") }
}