如何在RxJava中制作冷单曲

时间:2018-08-03 12:46:42

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

我有一些代码可以发出网络请求,并为每个请求返回一个Single

public Single<Response> getSomeData(String endpoint)    
{
    return Single.fromCallable(makeNewRequest(endpoint));
}

只要调用者实际上subscribes()到返回的Single,此方法就起作用。但是,在某些特定情况下(对于POST请求),调用者对结果不感兴趣,并且从不调用subscribe()

由于fromCallable()将执行推迟到订阅时间之前,这意味着该请求将不会被实际执行。

问题:将这个{冷} Single变成热点的正确方法是什么(惯用的)方法,以便无论呼叫者是否呼叫subscribe()都立即执行网络请求?

3 个答案:

答案 0 :(得分:2)

我想说您需要将publish运算符与connect结合使用。在此之前,您需要使用toObservable()

Single转换为Observable

另外,请注意,如果呼叫者对实际结果不感兴趣,则Completable套件可能会更好。您可以使用Single

Completable转换为toCompletable()

答案 1 :(得分:1)

您可以使用SingleSubject来为任何感兴趣的参与者缓存响应,但是请注意,您必须以某种方式向此API调用添加调度和可能的取消:

public Single<Response> getSomeData(String endpoint, 
        Scheduler scheduler, Consumer<? super Disposable> dispose) {

    Callable<Response> requestor = makeNewRequest(endpoint);
    SingleSubject<Response> result = SingleSubject.create();
    Disposable d = scheduler.scheduleDirect(() -> {
         try {
             result.onSuccess(requestor.call());
         } catch (Exception ex) {
             result.onError(ex);
         }
    });
    if (dispose != null) {
        dispose.accept(d);
    }
    return result;
}

请注意,尽管此设置现在确实很热,但您必须再次调用getSomeData()才能向同一端点发出新请求并获得新结果。

答案 2 :(得分:1)

我终于通过使用Single.cache()并订阅了一个虚拟观察者来解决了这个问题。这样,无论API客户端是否实际订阅了返回的observable,都将执行请求。代码如下:

public Single<Response> getSomeData(String endpoint)    
{
    Single<Response> res = Single.fromCallable(makeNewRequest(endpoint))
        .subscribeOn(Schedulers.io()) // if needed
        .cache();
    res.subscribe(dummyObserver);
    return res;
}

private static final SingleObserver<Response> dummyObserver = new SingleObserver<Response>() {
    public void onSubscribe(Disposable d) { }
    public void onSuccess(Response s) { }
    public void onError(Throwable e) { }
};

更新

这是不需要虚拟观察者对象的另一种方法:

public Single<Response> getSomeData(String endpoint)    
{
    Single<Response> res = Single.fromCallable(makeNewRequest(endpoint))
        .subscribeOn(Schedulers.io()); // if needed

    SingleSubject subject = SingleSubject.create(); 
    res.subscribe(subject);
    return subject;
}