Flow.collects receives items after it was cancelled on a single thread
See original GitHub issueCould anyone explain to me why this code throws an exception (on Android)? The collect
and cancel
functions are both called on the main thread. I tried this with both version 1.2.1 and 1.3.0-M1
var cancelled = false
val job = GlobalScope.launch(Dispatchers.Main) {
val flow = flow {
while (true) {
emit(Unit)
}
}
flow.flowOn(Dispatchers.IO)
.collect {
if (cancelled) { // main thread
throw IllegalStateException() // this exception is thrown
}
}
}
GlobalScope.launch(Dispatchers.Main) {
delay(1000)
job.cancel() // main thread
cancelled = true // set to true after the Flow was cancelled.
}
Here is an Android sample project, just run the app and it will crash.
I’m not sure if this is intended behaviour or a bug. I need to make sure all Flows are cancelled in the Android onDestroy
so they do not try to update the view if it is already gone. So if this is not a bug I am not sure how I would need to handle this otherwise.
There is a long discussion about this with more code examples on Slack: https://kotlinlang.slack.com/archives/C1CFAFJSK/p1559908916083600
We had some trouble trying to reproduce this in a unit test (it did not throw the exception), so that’s why I attached an Android project.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:13 (8 by maintainers)
I have replaced every single
collect
with asafeCollect
function in my project:It would be great if this could be implemented as a default as it’s really unexpected behavior and its error prone to always have to remember to not use specific library functions. On Android my collect functions are always right before they touch the views so they must not get invoked after the view is gone.
This is pretty unexpected to me but explains the issue with flows. This does feel like a very dangerous behavior on Android where objects tend to be nulled out in response to lifecycle methods. This would definitely not happen with RX since like @nickallendev said RX checks for cancellation both in the producer and consumer sides