我使用以下代码创建了一个observable。
Observable.create(new Observable.OnSubscribe<ReturnType>() {
@Override
public void call(Subscriber<? super ReturnType> subscriber) {
try {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(performRequest());
}
subscriber.onCompleted();
} catch (Exception e) {
subscriber.onError(e);
}
}
});
performRequest()
将按照您的预期执行长时间运行的任务。
现在,由于我可能会在很短的时间内启动相同 Observable两次或更多次,所以我决定编写这样的变换器:
protected Observable.Transformer<ReturnType, ReturnType> attachToRunningTaskIfAvailable() {
return origObservable -> {
synchronized (mapOfRunningTasks) {
// If not in maps
if ( ! mapOfRunningTasks.containsKey(getCacheKey()) ) {
Timber.d("Cache miss for %s", getCacheKey());
mapOfRunningTasks.put(
getCacheKey(),
origObservable
.doOnTerminate(() -> {
Timber.d("Removed from tasks %s", getCacheKey());
synchronized (mapOfRunningTasks) {
mapOfRunningTasks.remove(getCacheKey());
}
})
.cache()
);
} else {
Timber.d("Cache Hit for %s", getCacheKey());
}
return mapOfRunningTasks.get(getCacheKey());
}
};
}
这基本上将原始的.cache
可观察量放在HashMap<String, Observable>
中。
这基本上不允许使用相同getCacheKey()
(示例login
)的多个请求并行调用performRequest()
。相反,如果第二个login
请求到达而另一个请求正在进行中,则第二个请求可观察到达&#34;被丢弃&#34;并且将使用已经运行的。 =&GT;拨打onNext
的所有电话都将cached
,然后发送给两个实际上仅在我的后端点击一次的用户。
现在,支持此代码:
// Observable loginTask
public void doLogin(Observable<UserInfo> loginTask) {
loginTask.subscribe(
(userInfo) -> {},
(throwable) -> {
if (userWantsToRetry()) {
doLogin(loinTask);
}
}
);
}
loginTask由前一个变换器组成。好吧,当发生错误(可能是连接)和userWantsToRetry()
时,我基本上会用相同的observable重新调用该方法。不幸的是,这已被缓存,我会收到相同的错误而不会再次点击performRequest()
,因为序列会被重播。
有没有办法可以同时拥有&#34;相同的请求分组&#34;变压器为我提供的行为和重试按钮?
答案 0 :(得分:0)
你的问题很多,很难直接说出来。我可以提出一些建议。首先,您可以使用Observable.create
简化Observable.defer(Func0<Observable<T>>)
。这将在每次订阅新订阅者时运行func并捕获并引导订阅者onError的任何异常。
Observable.defer(() -> {
return Observable.just(performRequest());
});
接下来,您可以使用observable.repeatWhen(Func1<Observable<Void>, Observable<?>>)
来决定何时重试。重复运算符将在onComplete事件之后重新订阅observable。当收到onComplete事件时,此特定重载将向主题发送事件。您提供的功能将收到此主题。当您不想再次重试时,您的函数应调用类似takeWhile(predicate)
和onComplete的函数。
Observable.just(1,2,3).flatMap((Integer num) -> {
final AtomicInteger tryCount = new AtomicInteger(0);
return Observable.just(num)
.repeatWhen((Observable<? extends Void> notifications) ->
notifications.takeWhile((x) -> num == 2 && tryCount.incrementAndGet() != 3));
})
.subscribe(System.out::println);
输出:
1
2
2
2
3
上面的示例显示,当事件不是2并且最多重试22次时,重试会大声重复。如果切换到repeatWhen
,那么flatMap将包含您使用缓存的observable或realWork observable的决定。希望这有帮助!