Hey everyone, I'm looking for a solution to keep t...
# getting-started
c
Hey everyone, I'm looking for a solution to keep track of coroutines launched from a hot flow so I can cancel them if the same event arrives again. I've created this distilled example of combining a state flow but I'm not sure if this is safe/intended usage. Is updating state inside of the flow an anti-pattern?
Copy code
@Test
    fun start() {
        val sourceFlow = (0..20).asFlow()
        val stateFlow = MutableStateFlow(mutableMapOf<String, Int>())

        runBlocking {
            stateFlow.asStateFlow().combine(sourceFlow) { state, number ->
                println("got number $number")
                state[(number % 2).toString()] = number
                state
            }
                .take(20)
                .collect { result -> println("got result $result") }
        }
    }
I moved this from the #server section since this channel seemed more appropriate
s
It looks like you have a mutable state flow containing a mutable map here. Mutating the contents of the map will not mutate the value of the state flow. So based on your current code, I don’t think the value of the state flow ever changes.
c
I'm not sure if I need the stateFlow itself to change. I'm looking for a safe way to access state inside of a flow. A simple example is a hashmap in my class outside of the flow that I can get/put data but that doesn't seem right having the data outside of the flow scope
s
I would suggest wrapping the whole thing in a new flow:
Copy code
flow {
    val state = mutableMapOf<Whatever>()
    existingFlow.collect {
        state.doStuff()
    }
}.collect()
Bit of a noddy example, but the general idea should be flexible enough for whatever you need
c
yup makes sense, I didn't think to collect a different flow inside of a flow builder. I'll give that a shot, thanks!
e
that's how most of the flow transformations are implemented, so if you don't find one that matches your needs, that's what you get to do
c
awesome, good to know. thanks y'all
what if I don't need to emit a new value (no transformation of the event required) - would something like this still be safe for storing the state? It still feels weird collecting into an object outside of the flow but at least this is scoped close to the collect
Copy code
supervisorScope {
            // maintain a map of running jobs so that we can cancel them if needed.
            val runningJobs = mutableMapOf<Event, Job>()
            events.collect { event ->
                runningJobs[event]?.cancel("previous job was cancelled due to new event $event")
                runningJobs[event] = when (event) {
                    is EventOne -> handleEventOneAsync(event)
                    is EventTwo -> handleEvenTwoAsync(event)
                    is EventThree -> handleEventThreeAsync(event)
                }
            }
        }