I am trying to transform Observable using concatMap, since the order is important for my case.
#Test
fun load_data() {
val sub = TestSubscriber<Long>()
var s = BehaviorSubject.create<Long>()
s.concatMap {
Observable.timer(it, TimeUnit.MILLISECONDS)
}
.take(4)
.subscribe(sub)
s.onNext(5)
s.onNext(6)
s.onNext(7)
s.onNext(8) //rx.exceptions.MissingBackpressureException
sub.awaitTerminalEvent(500, TimeUnit.MILLISECONDS)
sub.assertNoErrors()
}
I have changed real data loading to Observable.timer() in order to simplify example and make it easier to reproduce.
I am using in the app BehaviorSubject to link UI actions with rx
From documentation, especially from marble diagram I expect that it will store items in queue and transform them one-by-one.
However it seems like concatMap has queue with size set only to 2 items. Adding more items cause MissingBackpressureException
So I have following questions:
Why concatMap has queue size 2 instead of RxRingBuffer.SIZE as
other operators has?
Should I as a rule add any of onBackpressure* operators before
calling concatMap to prevent from MissingBackpressureException
exception?
Before I answer the questions, please consider switching to RxJava 2 where this is be not a problem with an Observable.
Why concatMap has queue size 2 instead of RxRingBuffer.SIZE as other operators has?
The operator runs one Observable at a time and there was no reason to prefetch more than 1 in advance.
Should I as a rule add any of onBackpressure* operators before calling concatMap to prevent from MissingBackpressureException exception?
Yes.
Related
I am a newbie in RxJava. I want to combine three consecutive asynchronous operations in to chain by RxJava2:
fun getDataFromRESTApi(): Observable<TheData>
saveDataToCache(theData: TheData): Completable
getDataFromCache(): Observable<TheData>
How can I do this? What rxjava methods I could to use?
I'm not sure what you trying to achieve exactly but there's the concatMap operator :
getDataFromRESTApi()
.concatMap(theData -> saveDataToCache(theData).toObservable())
.concatMap(cachedData -> getDataFromCache()) //maybe not needed
In the other hand if saveDataToCache returns the saved data (cached) you don't need the third line.
Let's say I have a flowable, that some view is subscribed to and it's listening to the changes. I would like to add a custom method based on only the first emit of the flowable, but also keeping the other methods that listen to the changes. What is the best way to approach it?
The naive approach I have is to duplicate the flowable and convert it to Single or Completable to get the results, but it seems redundant.
Thank you.
Use .take(1). BTW also make sure that flowable is shared (otherwise some observers will miss events).
I think you can use share operator for that. Share operator makes a Connectable Observable. And then Connectable Observable publishes items each subscribes.
val o = Flowable.fromArray(1, 2, 3, 4, 5)
.map {
println("heavy operation")
it + it
}
.share() // publish the changes
.subscribeOn(Schedulers.computation()) // for testing. change what you want
o.take(1).subscribe { println("Special work: $it") } // take one
o.subscribe { println("Normal work: $it") }
Result
heavy operation
Special work: 2
Normal work: 2
heavy operation
Normal work: 4
heavy operation
Normal work: 6
heavy operation
Normal work: 8
heavy operation
Normal work: 10
I have been working with Rx Java 2 for awhile but recently came across a situation that has stumped me. I have a semi-complex chain of operations and wish to pass a "state object" down the chain.
There are 4 operations during which I wish to repeat operations 2 and 3 (serialy, not together) until certain conditions are true. I know i can solve this by chaining each operation using andThen(), but this limits my ability to pass a state object down the chain without reaching outside of the chain.
The reason I need to have a state object is because I need to save an initial value during the first operation and compare it to a value recieved during operation 4 to determine if the overall procedure was successful.
Any clues as to what RxJava2 operators can help me achieve the proper repeat conditions for operation 2 and 3? I would prefer to not nest observables if possible.
You can keep your state as some AtomicReference<State> and use repeatUntil operator.
AtomicReference<State> state = new AtomicReference<>();
Completable operation = Completable.create() // do something and modify state
.repeatUntil(() -> state.get() == SATISFYING_CONDITION);
You can easily chain these Completables with andThen
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.
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.