我们可以使用cache()运算符来避免多次执行长任务(http请求),并重用其结果:
Observable apiCall = createApiCallObservable().cache(); // notice the .cache()
---------------------------------------------
// the first time we need it
apiCall.andSomeOtherStuff()
.subscribe(subscriberA);
---------------------------------------------
//in the future when we need it again
apiCall.andSomeDifferentStuff()
.subscribe(subscriberB);
第一次执行http请求,但第二次,因为我们使用了cache()运算符,请求将不会被执行,但我们将能够重用第一个结果。
当第一个请求成功完成时,这工作正常。但是,如果在第一次尝试中调用 onError ,那么下次新订阅者订阅同一个可观察值时,将再次调用 onError ,而无需再次尝试 http 请求。
我们想要做的是,如果第一次调用 onError,那么下次有人订阅同一个可观察对象时,将从头开始尝试 http 请求。即 observable 将仅缓存成功的 api 调用,即调用 onCompleted 的那些调用。
关于如何继续的任何想法?我们尝试过使用 retry() 和 cache() 运算符,但运气不佳。
这是我们在扩展 akarnokd 的解决方案后最终得到的解决方案:
public class OnErrorRetryCache<T> {
public static <T> Observable<T> from(Observable<T> source) {
return new OnErrorRetryCache<>(source).deferred;
}
private final Observable<T> deferred;
private final Semaphore singlePermit = new Semaphore(1);
private Observable<T> cache = null;
private Observable<T> inProgress = null;
private OnErrorRetryCache(Observable<T> source) {
deferred = Observable.defer(() -> createWhenObserverSubscribes(source));
}
private Observable<T> createWhenObserverSubscribes(Observable<T> source)
{
singlePermit.acquireUninterruptibly();
Observable<T> cached = cache;
if (cached != null) {
singlePermit.release();
return cached;
}
inProgress = source
.doOnCompleted(this::onSuccess)
.doOnTerminate(this::onTermination)
.replay()
.autoConnect();
return inProgress;
}
private void onSuccess() {
cache = inProgress;
}
private void onTermination() {
inProgress = null;
singlePermit.release();
}
}
我们需要缓存来自 Retrofit 的 http 请求的结果。因此,它被创建了,并带有一个发出单个项目的可观察对象。
如果观察者在执行 http 请求时订阅,我们希望它等待并且不会执行该请求两次,除非正在进行的请求失败。为此,信号量允许对创建或返回缓存的可观察量的块进行单次访问,如果创建了新的可观察量,我们将等待该可观察量终止。对以上内容进行测试可以发现here https://github.com/platoblm/rx-onerror-retry-cache/blob/master/src/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)