RxJava2 - Emitting items using PublishSubject - android

I've a scenerio where I've
subject1: PublishSubject and subject2:BehaviorSubject.
First, I emit single item for subject1, then I emit item for subject2, but right after that I also want to emit different item to subject1.
fun emittingItems() {
subject1.onNext(functionA1)
subject2.onNext(functionB)
if (something) subject1.onNext(functionA2)
}
What happens is, that I receive an item in this sequence: functionA1, functionA2, functionB.
Why do I get this behavior? How can I emit items in this sequence: functionA1, functionB,functionA2.
Subscribing to subjects:
val disposable = viewModel.subject1
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::someFunction())
disposables.add(disposable)

With observeOn(AndroidSchedulers.mainThread()) you schedule the propagation of events on the main thread. The scheduling itself is sequential, while each scheduled Runnable might handle more than one element added to the queue used for it.
It's a kind of race condition which will arise for sure when calling emittingItems() on the main thread itself and could arise when calling it from any other thread.
But since you're handling two different asynchronous streams, you cannot expect any sequential observation within the two different observers.
You can achieve the given, by merging both sources as one stream:
Observable.merge(subject1, subject2)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subject);

Related

Ensure sequential state update when using RXJava scan operator

I'm trying to implement redux state update pattern using RXJava
val subject=PublishSubject.create()
val subject1=PublishSubject.create()
// multiple threads posting
// on subject and subject1 here. Concurrently
subject.mergeWith(subject1)
.scan(
getInitState(),
{state, event ->
// state update here
}
)
.subscribe({state ->
// use state here
})
As you can see, I'm using scan operator to maintain the state.
How can I be sure that the state updates happen sequentially even when multiple threads are producing events?
Is there some mechanism in scan operator which makes the events stand in some queue while waiting for current state update function to finish?
What I have done:
I have successfully implemented this pattern in Android environment. It's really easy because if you always do the state update in
AndroidSchedulers.mainThread()
And make state object immutable you are guaranteed to have atomic and sequential state update. But what happens if you don't have dedicated scheduler for state updates? What if you are not on Android?
What I have researched:
I have read the source code for scan operator and there is no
waiting "queue" involved. Just simple state update and emission
I have also read SerializedSubject source code. There indeed is a waiting queue which serializes emissions. But what happens if I have two subjects? Serializing both of them doesn't mean that they don't interfere with each other.
To force execution on a single thread, you can explicitly create a single thread scheduler to replace AndroidSchedulers.mainThread():
val singleThreadScheduler = Schedulers.single()
Even if the events are emitted on other threads, you can ensure you process them only on your single thread using observeOn:
subject.mergeWith(subject1)
.observeOn(singleThreadScheduler)
.scan(
getInitState(),
{state, event ->
// state update here
}
)
.subscribe({state ->
// use state here
})
The difference between observeOn and subscribeOn can be pretty confusing, and logging the thread id can be useful to check everything is running on the thread you expect.
http://reactivex.io/documentation/scheduler.html

Is it possible to implement an operator like delay but that also delays errors?

I'm trying for some time now to implement an extension function (just becuse it's easier to me) that is capable of delaying both normal item emissions and errors. The existing delay operators only delays normal item emissions, errors are delivered ASAP.
For context, I'm trying to immitate an Android LiveData's behavior (kinda). LiveDatas are a observable pattern implementation that is lifecycle aware. Their observers are only notified if they are in a state where they can process that emission. If they are not ready, the emission is cached in the livedata and delivered as soon as they become ready.
I created a BehaviourSubject that emits the state of my Activities and Fragments when it changes. With that I created a delay operator like this:
fun <T> Flowable<T>.delayUntilActive(): Flowable<T> = delay { lifecycleSubject.toFlowable(BackpressureStrategy.LATEST).filter { it.isActive } }
and then use it like this
myUseCase.getFlowable(Unit)
.map { it.map { it.toDisplayModel() } }
.delayUntilActive()
.subscribe({
view.displaySomethings(
}, { }).addTo(disposables)
So even if myUseCase emits when the view is not ready to display somethings, the emission won't reach onNext() until the view does become ready. The problem is that I also want the view to displayError() when onError is triggered, but that too is lifecycle sensitive. If the view isn't ready, the app will crash.
So I'm looking for a way to delay both emissions and errors (onComplete would be good too). Is this possible?
I tried some things with zip, onErrorReturn, delay inside delay, but nothing seemed right. I'd be equally unimpressed if this had a really easy solution I'm overlooking, or is impossible. Any ideas are welcome.
Bonus: any better way to do that for Single and Completable too? currently I'm just converting them to flowable.
Thanks in advance!
You can handle the error via onErrorResumeNext, then taking the same error and delaying it via delaySubscription until your desired signal to emit said error happens:
source
.onErrorResumeNext({ error ->
Observable.error(error)
.delaySubscription(lifecycleSubject.filter { it.Active } )
})

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:
Apply consistent schedulers
Handle any error by returning an instance of my sealed class.
Handle any onNext by publishing the state returned by the observable.
Start off by sending a Loading state.
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.
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.

Mutable list of Obersable<Object> wait until all of them finish and combine them into a List<Object>

I'm not an expert in RxJava/RxAndroid and I'm having some issues with this scenario.
Basically I have a mutable list of observable which I won't ever know the size and I want to wait until all of them are completed as well.
var observableList: MutableList<Observable<Object>> = mutableListOf()
And I would like to do something like:
Observable.zip(observableList,....)
and combine all the Object results into Object<List>
You can use Observable.concat() for this and call toList() on it.
Observable.concat(observableList)
.subscribeOn(...)
.toList()
.observeOn(...)
.subscribe(...)
Inbetween you can also switch threads with subscribeOn and observeOn to make sure not to block the UI thread.

RxJava - How can I set thread for observeOn dynamically?

Let's say I have following code.
Scheduler ioSC = getIOThread();
Scheduler mainSC = AndroidSchedulers.mainThread();
Subscription subs = getObservable()
.doOnNext(getAction1())
.doOnSubscribe(getAction2())
.observeOn(/****TODO***/)
.subscribe(getSubsAction());
In this code, I want to be able to set the thread for observeOn() based on the type if item I get from getObservable().
How can I add this condition checking in this subscription?
Is it even possible to dynamically set a thread for observeOn()?
Thanks!
You could use flatMap() for this:
getObservable()
.doOnNext(getAction1())
.doOnSubscribe(getAction2())
.flatMap(item -> Observable.just(item).observeOn(getScheduler(item)))
.subscribe(getSubsAction());
But then the question comes up, why would you handle different items on different threads using the same subscriber. This seems a little off and you might want to reconsider your chain.

Categories

Resources