在运行另一个observable之前使用concatMap运行Single

时间:2018-03-19 16:21:32

标签: kotlin rx-java concatmap

Android Studio 3.1 RC 2
kotlin 1.2.30

Java中fetchMessage的签名

Single<Response> fetchMessage(final String Id); 

kotlin代码

fun translate(Id: String): Completable {
        return repository.fetchMessage(Id)
                .flatMap {
                    Single.fromCallable<State>({
                        update(messageId, it, State.COMPLETED)
                        State.COMPLETED
                    })
                }
                .onErrorReturn({
                    update(Id, null, State.ERROR)
                    State.ERROR
                })
                .toCompletable()
    }

我想在fetchMessage

之前运行的方法
 fun insertMessage(Id: String): Completable {
        return Completable.fromCallable {
            insert(Id, State.IDLE)
        }
    }

我希望insertMessage e以某种方式在fetchMessage之前运行。我在考虑使用concatMap但不确定如何组合translate和insertMessage。这样insertMessage将首先运行,然后一旦完成,将运行translate。

非常感谢任何建议,

Update solution 1 using startWith(..):

通过将translate方法的返回值更改为Single。我这样做了:

fun translate(Id: String): Single<State> {
        return repository.fetchMessage(Id)
                .flatMap {
                    Single.fromCallable<State>({
                        update(messageId, it, State.COMPLETED)
                        State.COMPLETED
                    })
                }
                .onErrorReturn({
                    update(Id, null, State.ERROR)
                    State.ERROR
                })
    }

然后我可以有一个方法来执行以下insertMessage(..) - &gt;翻译(..):

translate(Id).toCompletable().startWith(insertMessage(id, State.IDLE))

这会是一个理想的解决方案吗?

Update solution 2 using concatWith(..):

我返回一个Observable并在链中调用toObservable()。

fun translate(Id: String): Observable<State> {
        return repository.fetchMessage(Id)
                .flatMap {
                    Single.fromCallable<State>({
                        update(messageId, it, State.COMPLETED)
                        State.COMPLETED
                    })
                }
                .onErrorReturn({
                    update(Id, null, State.ERROR)
                    State.ERROR
                })
                .toObservable()
    }

我可以使用concatWith,因此序列将是insertMessage(..) - &gt;翻译(..):

translate(Id).toCompletable().concatWith(insertMessage(id, State.IDLE).toObservable())
    .toCompletable()

这些是正确的解决方案吗?

2 个答案:

答案 0 :(得分:5)

如果您有Completable,则可以通过andThen链接任何其他被动类型:

insertMessage("id")
.andThen(translate("id"))

答案 1 :(得分:2)

你的选择都有道理,但我建议你稍微清理一下。

首先,您需要清楚地了解每种情况下要使用的返回类型:ObservableSingleCompletable

定义如下:

  • 单个表示发出单个值或错误的Observable。
  • 可完成表示不发送任何值的Observable,但只发出onError或onCompleted的终端事件。

在您的两种情况下,您都不需要返回任何数据,您只需知道操作是否成功。 Completable旨在处理这种情况。

所以我建议您:

UISpellDatabase.Instance.spells.Add(new UISpellInfo());

让您的代码更清晰的不错选择是使用Completable.fromAction代替Completable.fromCallable,因此您不需要返回任何内容。

然后,您可以使用任何选项,startWithconcatWith。两者都等到第一个observable完成后再运行第二个observable。我更喜欢使用concatWith,因为它以与编写它们相同的顺序运行函数。

最终我们得到了一个优雅的解决方案:

fun translate(Id: String): Completable {
    return repository.fetchMessage(Id)
             .flatMapCompletable {
                Completable.fromAction {
                  update(messageId, it, State.COMPLETED)
                }
             }.doOnError {
                update(Id, null, State.ERROR)
             }
}

fun insertMessage(Id: String): Completable {
    return Completable.fromCallable {
        insert(Id, State.IDLE)
    }
}

insertMessage(id).concatWith(translate(id))

有关concat的更多信息:http://reactivex.io/documentation/operators/concat.html

如果你很好奇,这里是rxJava库中函数的实现:

translate(id).startWith(insertMessage(id))

正如您所看到的,唯一的区别是订单。