Is StateFlow acceptable to use for short running o...
# coroutines
s
Is StateFlow acceptable to use for short running operations where I need a flow of data? State flows don’t complete, so the collection of them doesn’t stop right?
m
Downstream collection of
StateFlow
stops as usual. But
StateFlow
doesn’t stop collecting from upstream.
What’s the use case?
s
If I were to have a short running operation, i.e. a File Download, and I wanted to return a progress of how much of the download has completed. I wouldn’t want to use
Copy code
flow {
  // Do download here
  emit(progress)
}
Because then I’d be blocking my download thread with potentially backed up emit calls.
Doing something like
Copy code
val stateFlow = MutableStateFlow()
launch(<http://Dispatchers.IO|Dispatchers.IO>) {
  // Do Download
  stateflow.value = progress
}
return stateFlow
would solve that, but I don’t think the state flow would work here. Whoever collected from it would never stop collecting, right?
I have no way to
complete
the
StateFlow
m
StateFlow
works perfect for download progress. You can force the downstream collectors to stop collecting when the download is complete.
You’d use
completeWhenDone
on your
StateFlow
c
There’s nothing wrong with the
flow { }
builder, this is a perfectly normal use-case, and is a better fit than StateFlow. Using
.flowOn(<http://Dispatchers.IO|Dispatchers.IO>)
will allow the upstream producer to run on background threads, while the downstream collector will collect in the main thread. https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/flow-on.html
m
You should use
StateFlow
only when you actually have to maintain a state (i.e. the last 1+ values) for collectors 🙂
k
Because then I’d be blocking my download thread with potentially backed up emit calls.
offer
?
you could convert your
flow
to
channelFlow
and make the download progress a callback. Then offer from there. offer only emits events if the downstream collectors aren’t applying backpressure
c
Alternatively,
.conflate()
the flow, so emissions are simply dropped if the collector is slow and can’t keep up https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/conflate.html Or
.debounce()
to set a particular delay time between emissions, dropping the rest https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/debounce.html
s
Thanks for the suggestions. @Casey Brooks Would you recommend conflating before or after
.flowOn
?
c
Probably after, but I don’t think it would matter much. By design, the main thread will put backpressure on the emissions in the same way due to the sequential nature of the Flow, but the actual conflation is processed in a separate coroutine from both the collector and the producer