我的应用程序中有许多用于网络请求的Observable。由于有很多相同之处,因此我对它们进行了可观察的转换:

/**
 * Creates a transformer that applies the schedulers and error handling for all of the observables in this ViewModel.
 */
private fun applyTransformations(): Observable.Transformer<NetworkState, NetworkState> {
    return Observable.Transformer { observable ->
        observable
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .onErrorReturn { NetworkState.Error(it) }
                .doOnNext { publishState(it) }
                .startWith(NetworkState.Loading())
    }
}


我试图通过以上目标实现的目标:


应用一致的调度程序
通过返回我的密封类的实例来处理任何错误。
通过发布可观察者返回的状态来处理任何onNext。
通过发送加载状态开始。


这在大多数情况下都可以正常工作,但是我注意到的是,虽然我调用startWith和加载状态,但实际上并没有由doOnNext()处理。换句话说,publishState()永远不会调用我的加载状态。

在我设置可观察对象的地方,我不必费心添加一个订户,因为上面的doOnNext()是我所需要的:

val subscription = repository.getInstagramPhotos(count)
        .map { mapIGPhotoResponse(it) }
        .compose(applyTransformations())
        .subscribe()


但是,如果我要在上面提供一个订户,它将处理加载状态。它还将处理两个onNext()调用-一个用于提供的订户,一个用于doOnNext转换。

有没有办法修改此startWith调用以发出我在doOnNext中指定的内容?我正在使用RxJava 1。

编辑:只是要澄清更多,如果我跟踪发出了什么,我希望看到两件事。 Loading -> Success。我实际看到的只是Success。如果我为可观察对象提供订户,则会看到Loading -> Success -> Success

最佳答案

startWith应该在doOnNext之前。

Rxjava方法虽然看起来好像使用了构建器模式,但实际上却没有。每次应用运算符时,它们都会返回一个新的可观察值。在您的情况下,您的doOnNext observable在您开始使用observable之前完成,因此不会使用startWith中提供的内容来调用它的使用者。

理想情况下,您应该选择:

observable
                .startWith(NetworkState.Loading())
                .doOnNext { publishState(it) }
                .onErrorReturn { NetworkState.Error(it) }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())


另外,如果没有onEror订阅,请谨慎行事。由于您没有任何消耗onError的内容,因此RxJava将使您的应用程序崩溃,因为它没有任何通知错误的信息。如果您想忽略它,请考虑将doOnNext替换为subscribe中的Success使用者,并使用一个空的Consumer作为错误。

同样,doOnNext通常用于副作用,例如日志记录和排序,它们比真正的函数运算符更方便。

10-08 06:59