Stylianos Gakis
06/15/2023, 12:05 PMstateIn(scope, WhileSubscribed(), ...)
so that it’s live only when there are subscribers, and it starts collecting the flow each time there’s a new subscriber after it was “not live” for any period of time.
While this is live, I want to also be running another coroutine, which will do some networking, doesn’t matter, what does matter is that I need to be in a suspend context.
What I’ve done now is basically
combine(
flow<Unit> { emit(Unit) Must emit Unit so the combine doesn't get stuck waiting for this flow to emit something ; here I do this work that I mention },
someFlowINeedTheResultFrom<Int>(),
someFlowINeedTheResultFrom#2<String>(),
) { _, someInt, someString ->
// handle the two things I need, simply ignore the first item
}.stateIn(scope, WhileSubscribed(), ...)
But it feels really awkward to put it in the combine just to get the right scope for when it should run, while ignoring the result.
Another thing I considered was something like
combine(
someFlowINeedTheResultFrom<Int>(),
someFlowINeedTheResultFrom#2<String>(),
) { _, someInt, someString ->
// handle the two things I need, simply ignore the first item
}
.onStart {
flow { here I do this work that I mention }.collect {
// <---
},
}
.stateIn(scope, WhileSubscribed(), ...)
But now while I am on a suspending context, it’s actually blocking the first emission, since it will try to run to a finish before the result of my combine will emit something. I’d optimally want this to be a launch
in there, but I can’t do that either since I am not inside some sort of CoroutineScope
, but just have access to the CoroutineContext of the flow, where I can’t do such launches, while still making sure that it’s cancelled when the last subscriber drops.
Any thoughts on this? Is my first approach my best bet here?alex.krupa
06/15/2023, 3:21 PMbut I can't do that either since I am not inside some sort ofYou can use the coroutineScope builder to create a scope with parent'sCoroutineScope
CoroutineContext
.Stylianos Gakis
06/15/2023, 3:23 PM律素
06/15/2023, 4:43 PMviewModelScope.launch (<http://Dispatchers.IO|Dispatchers.IO>) {}
in onStart{}
or use SharedFlow to emit values in onStart{}
and onCompletion{}
to notify the start and end of another flow.Stylianos Gakis
06/15/2023, 7:11 PM律素
06/16/2023, 6:23 AMAlso I wonder if onCompletion is called in this particular case of all the observers being dropped.
OnCompletion
is called when the flow emits all events or the subscriptionCount of flow is changed to 0. And the stateIn() with WhileSubscribed() makes the flow restart when the subscriptionCount changes from 0 to a value gt 0.
Using onStart
and onCompletion
can indeed make the problem more complex. Your first solution can solve this problem, and I think merge
can be used to replace the `emit(Unit)`:
val stateFlow = merge(
flow<Unit> { /* do your work */ },
combine(
flowOf(0, 1, 2),
flowOf("A", "B", "C")
) { a, b ->
// handle the two things
}
).stateIn(scope, SharingStarted.WhileSubscribed(), initialValue)
myanmarking
06/16/2023, 8:04 AM