可观察序列终止时的异步清理

时间:2017-07-31 04:41:51

标签: rx-java

我需要对可观察的完成/失败执行异步方法(例如清理作业)。此外,如果清理方法失败,则可观察链也应该失败。

有没有一种标准的方法可以做到这一点?

假设我有一个序列Observable source和asyncCleanup()方法,它返回一个可观察的清理结果。

doOnCompleted / doOnTerminate / doOnUnsubscribe等副作用方法似乎不合适:

source.doOnUnsubscribe(()->asyncCleanup().subscribe());

即使asyncCleanup()失败,observable链也会成功。 所以asyncCleanup()应该是同一个链的一部分。

我想出的最好成绩如下:

source.onErrorResumeNext(err->asyncCleanup()
         .flatMap(cleanupResult->Observable.error(err)))
      .concatWith(asyncCleanup()
         .flatMap(cleanupResult->Observable.empty()));

如果失败,onErrorResumeNext将调用asyncCleanup()并将映射回原始错误。 如果成功,我们可以与映射到空序列的asyncCleanup()连接。 不幸的是,如果下游有一个take()或类似的限制运算符,它就无法工作,这可能会导致连接的observable甚至不能订阅。

更新2017-08-01 : 问题是关于序列可观察的。对于单项可观察源,解决方案非常简单:

singleItemSource
    .onErrorResumeNext(err->asyncCleanup()
        .flatMap(cleanupResult->Observable.error(err)))
    .flatMap(single->asyncCleanup()
        .map(cleanupResult->single));

3 个答案:

答案 0 :(得分:1)

您提出的想法违反了Observable合同,因为:

  

Rx设计指南 ,6.8 - 取消订阅不应抛出

我想到的唯一解决问题的方法是将asyncCleanup()转换为前一个序列的相同类型,如果成功返回例如Observable.empty(),则可以使用concat运营商。

public Observable<Long> asyncCleanup() {
...
    return Observable.empty();
}

//Concat asyncCleanup() to be executed after the sequence
Observable.rangeLong(1, 10)
            .concatWith(asyncCleanup())
            .subscribe(System.out::println, System.out::println);

希望它有所帮助...

答案 1 :(得分:1)

有一个flatMap重载,您可以将上游的onXXX事件映射到Observable s:

Observable.range(1, 10)
    .flatMap(Observable::just, e -> asyncCleanup(), () -> asyncCleanup())
    .subscribe(...);

答案 2 :(得分:0)

我评论avobe的另一个解决方案是工厂方法Observable.using。这是一个简单的例子:

Observable<Long> range = Observable.rangeLong(1, 10);

Observable.using(() -> range, //The resource provider
            observable -> observable, //The resource
            observable -> asyncCleanup() //The resource disposer
                     .subscribe(System.out::println, System.out::println))
    .subscribe(System.out::println, System.out::println);

这里的缺点是你应该处理asyncCleanup()成功和错误,而不会传播或抛出。使用这种方法,您应该考虑在asyncCleanup()方法的情况下远离Observable。

相关问题