AdamMc331
AdamMc331

Reputation: 16691

Observable startWith isn't emitted in doOnNext

I have a number of Observables that are used for network requests in my app. Since so much is the same, I apply an Observable transformation to them:

/**
 * 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())
    }
}

The goals I am trying to accomplish with the above:

This works mostly fine, but what I've noticed is that while I call startWith and a loading state, it is never actually handled by doOnNext(). In other words, publishState() is never called for my loading state.

Where I set up the observables, I don't bother to add a subscriber, because the doOnNext() above is all that I'll need:

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

If I were to supply a subscriber above, though, it would handle the loading state. It would also handle two onNext() calls - one for the subscriber supplied, and one for the doOnNext in the transform.

Is there a way to modify this startWith call to emit to whatever I've specified in doOnNext? I'm using RxJava 1.

Edit: Just to clarify some more, if I track what's emitted I expect to see two things. Loading -> Success. What I actually see is just Success. If I supply a subscriber to the observable I see Loading -> Success -> Success.

Upvotes: 1

Views: 530

Answers (1)

Tunji_D
Tunji_D

Reputation: 3687

startWith should be before doOnNext.

Rxjava methods, though they look like they use the builder pattern, actually don't. They return a new observable each time an operator is applied. In your case, your doOnNext observable completes before your start with observable, so it's consumer isn't called with what you supply in startWith.

Ideally, you should go with:

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

Also, be careful with subscribing with no Consumer for onEror should it happen. Since you have nothing to consume the onError, RxJava will crash your app since it has nothing to notify for the error. Consider replacing the doOnNext with a Success Consumer in subscribe, and an empty Consumer for the error if you want to ignore it.

Also doOnNext is typically used for side effects, such as logging and the sort, they're more of a convenience than true functional operators.

Upvotes: 5

Related Questions