Reputation: 16691
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
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