https://kotlinlang.org logo
#coroutines
Title
# coroutines
s

spierce7

02/19/2021, 6:01 PM
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

Marc Knaup

02/19/2021, 6:02 PM
Downstream collection of
StateFlow
stops as usual. But
StateFlow
doesn’t stop collecting from upstream.
What’s the use case?
s

spierce7

02/19/2021, 6:05 PM
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

Marc Knaup

02/19/2021, 6:07 PM
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

Casey Brooks

02/19/2021, 6:10 PM
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

Marc Knaup

02/19/2021, 6:11 PM
You should use
StateFlow
only when you actually have to maintain a state (i.e. the last 1+ values) for collectors 🙂
k

kevin.cianfarini

02/19/2021, 6:56 PM
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

Casey Brooks

02/19/2021, 7:06 PM
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

spierce7

02/19/2021, 7:09 PM
Thanks for the suggestions. @Casey Brooks Would you recommend conflating before or after
.flowOn
?
c

Casey Brooks

02/19/2021, 7:12 PM
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
4 Views