I'm writing an Rx-based unidirectional UI flow where each state reduce is a Single. Usually such flows are done with scan (they need previous state), but when Single is involved it's a bit tricky. I managed to get it working like this:
val events = Observable.just("event1", "event2", "event3")
val initialState = Single.just(emptyList<String>())
// given a current state produces next state's Single
val reducer = { currentState: List<String>, event: String ->
Single.fromCallable { /* do work */ currentState.plus(event) }
}
events
.scan(
initialState,
{ currentStateSingle, event ->
val nextStateSingle = currentStateSingle
.flatMap { curState -> reducer(curState, event) }
// cache is required to avoid resubscription
// to all previously emitted single's on each new scan iteration
nextStateSingle.cache()
}
)
.flatMapSingle { it }
.subscribe { state -> println("state updated to $state") }
What bothers me is that each event (of which there can be many in UI environment) will create a nextStateSingle.cache() and forever add it to an existing chain and all those Singles ever emitted will stay there, unboundedly consuming memory and never being disposed while after they emitted a new state once, they are not needed at all.
I've been thinking on how to do this with some kind of switchMap usage, or even using some external atomic variable to hold state (instead of scan), but I fail to find a way.
The only other option I see is to write a custom operator which will subscribe to inner single, wait for result then dispose it, but I'd like to avoid writing a custom operator.