如何取消/取消协程流程 [英] How to cancel/unsubscribe from coroutines Flow
问题描述
当我尝试过早地从Flow中取消时,我注意到一个奇怪的行为.看下面的例子.
I notice a strange behavior when trying to prematurely cancel from a Flow. Take a look at the following example.
这是一个发出整数值的简单流程
This is a simple flow that emits integer values
private fun createFlow() = flow {
repeat(10000) {
emit(it)
}
}
然后我使用此代码调用createFlow
函数
Then I call the createFlow
function using this code
CoroutineScope(Dispatchers.Main).launch {
createFlow().collect {
Log.i("Main", "$it isActive $isActive")
if (it == 2) {
cancel()
}
}
}
这是打印出来的
0 isActive true
1 isActive true
2 isActive true
3 isActive false
4 isActive false
etc...etc
现在,我希望流一旦达到2的值就应该停止发出整数,但是实际上它将isActive标志切换为false并保持发出而不会停止.
Now I would expect that the flow should stop emitting integers once it reaches the value of 2 but instead it actually switches the isActive flag to false and keeps emitting without otherwise stopping.
当我在两次发射之间添加延迟时,流量的行为将达到我的预期.
When I add a delay between emissions the flow behaves as I would expect.
private fun createFlow() = flow {
repeat(10000) {
delay(500) //add a delay
emit(it)
}
}
这是在再次调用流程(预期的行为)之后打印出来的内容.
This is what is printed out after calling the flow again (which is the expected behaviour).
0 isActive true
1 isActive true
2 isActive true
如何在不增加延迟的情况下精确地取消流量排放?
What can I do to cancel the flow emission exactly at the specified value without adding delay?
推荐答案
我在我在项目中用safeCollect
函数替换了每个collect
:
I have replaced every single collect
with a safeCollect
function in my project:
/**
* Only proceed with the given action if the coroutine has not been cancelled.
* Necessary because Flow.collect receives items even after coroutine was cancelled
* https://github.com/Kotlin/kotlinx.coroutines/issues/1265
*/
suspend inline fun <T> Flow<T>.safeCollect(crossinline action: suspend (T) -> Unit) {
collect {
coroutineContext.ensureActive()
action(it)
}
}
这篇关于如何取消/取消协程流程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!