组合两个Observable流时如何发出最终值?

时间:2018-04-08 23:01:14

标签: android kotlin rx-java

使用杰克沃顿的Managing State with RxJava模式。

我将两个api调用组合在一起并行执行。

我如何发出成功"两者都完成后的项目?

请参阅以下代码中的评论。

谢谢!

主要通话功能:

    Observable
            .just(UpdatePicEvent(userId, file))
            .compose(updatePic()) <-- Handles updating pic, emits models consumed by UI
            .mergeWith(
                    Observable
                        .just(UpdateProfileEvent(..params...))
                        .compose(updateProfile()) <-- Handles updating other settings, emits models consumed by UI
            )

            // TODO Need to add something to emit a Success() model item when both actions above have completed  

            .subscribe(...pass models to UI...)

updatePic()

fun updatePic(): ObservableTransformer<UpdatePicEvent, ProfileSettingsModel> {
        return ObservableTransformer {
            it.flatMap {
                api.uploadProfilePic(it.userId, it.pic)
                    .map { UpdatePicSuccessful(it) as ProfileSettingsModel }
                    .onErrorReturn { UpdatePicError(it) as ProfileSettingsModel }
                    .startWith(UpdatePicInProgress() as ProfileSettingsModel)
            }
        }
    }

updateProfile()

fun updateProfile(): ObservableTransformer<UpdateProfileEvent, ProfileSettingsModel> {
        return ObservableTransformer {
            it.flatMap {
                api
                    .updateUser(...params...)
                    .subscribeOn(Schedulers.io())
                    .map { UpdateProfileSuccessful(it) as ProfileSettingsModel }
                    .onErrorReturn { UpdateProfileError(it) as ProfileSettingsModel }
                    .observeOn(AndroidSchedulers.mainThread())
                    .startWith(UpdateProfileInProgress() as ProfileSettingsModel)
            }
        }
    }

2 个答案:

答案 0 :(得分:0)

您收到两个不同的ProfileSettingsModel您需要合并。如果您不想在订阅者中执行此操作,则可以使用zip operator来实现您的链。

  

通过指定的函数将多个Observable的排放组合在一起,并根据此函数的结果为每个组合发出单个项目

Observable.zip(
    Observable.just(UpdatePicEvent(userId, file)).compose(updatePic())
    Observable.just(UpdateProfileEvent(..params...)).compose(updateProfile())
    mergePicAndProfile)

mergePicAndProfileBiFunction接收两个结果并发出单个实体的地方。

答案 1 :(得分:0)

鉴于您对原始问题的评论,concat可以为您提供帮助。文档的相关部分说:

  

Concat运算符连接多个Observable的输出,使它们像单个Observable一样,第一个Observable发出的所有项在第二个Observable发出的任何项之前发出(等等,如果有的话)超过两个。)

     

Concat等待订阅您传递给它的每个其他Observable,直到上一个Observable完成。

实现:

Observable.mergeDelayError(
    Observable.just(UpdatePicEvent(userId, file)).compose(updatePic()),
    Observable.just(UpdateProfileEvent(userId, params)).compose(updateProfile())    
)
    .concatWith(Observable.just(AllSuccessful()))  // Or whatever
    .onErrorReturn { when (it) {
        is UpdatePicException -> UpdatePicError(it)
        is UpdateProfileException -> UpdateProfileError(it)
    }}

这有两个关键因素:

  1. 您需要替换onErrorReturnupdatePic变换器中的updateProfile,以便它们在失败时实际发出错误(可能是onErrorResumeNext { Observable.error(MyTypeOfException()) }之类的内容。要做到这一点,流无法知道是否有错误(因为在项目中包装错误会使其与成功无法区分)
  2. 使用mergeDelayError让每个流独立于另一个流继续。如果您只使用merge,则第一个失败将阻止另一个继续。
  3. (请注意,我稍微修改了原始代码,恕我直言,更具可读性)