If I have a StateFlow, what is the best way to map it to another StateFlow? I get a Flow back from `...
a
If I have a StateFlow, what is the best way to map it to another StateFlow? I get a Flow back from
map
, but if I want it to be a StateFlow again I need to use
stateIn
but then I require a scope. Or is the mapped result still a stateflow? The usecase is I have a class that I want to expose a StateFlow which is based on another one. But if I want to use
stateIn
I need to do this from a coroutine. So it becomes something like this:
Copy code
interface History {
    val activeLocation: StateFlow<Location>
    // ...
}

class Router<R>(
    private val history: History,
    private val routing: Routing<R>,
    private val scope: CoroutineScope
) {
    lateinit var activeRoute : StateFlow<R>
        private set

    init {
        scope.launch {
            activeRoute = history.activeLocation
                .map { location -> routing.getRoute(location) }
                .stateIn(scope)
        }
    }
}
I am not sure if this is the most optimal way of doing it... I have the feeling I am overcomplicating stuff.
r
That’s how I’ve done it typically. I’m not sure you need that
scope.launch
though.
a
Well, stateIn is suspending, so I can't start it from within init normally I suppose
a
That is exactly what I needed! Thanks!
h
Well, stateIn is not suspending if you provide an initial value. Otherwise, it have to wait until a first value, so it is suspending
j
You should do a stateIn with the other parameters:
val myFlow = otherFlow.stateIn(scope, Eagerly, <defaultValue>
so in your case:
Copy code
activeRoute = history.activeLocation().map {..}.stateIn(scope, Eagerly, <defaultValue>)
the whole point of stateflow is that they always have a state
using lateinit is not a good solution for this (because then you are at times without a state
a
@Joost Klitsie you're absolutely right. I've modified my code to this