Zhanna Gorelova
06/29/2022, 11:11 AMclass CoroutineTest {
@Test
fun `test`() = withContext { context ->
// when
SomethingWithFlow(context)
//then
assertNotNull(context[Job])
}
private fun withContext(context: CoroutineContext = <http://Dispatchers.IO|Dispatchers.IO>, block: suspend (CoroutineContext) -> Unit) {
runBlocking(context) { block(context) }
}
class SomethingWithFlow(override val coroutineContext: CoroutineContext) : CoroutineScope {
private val flow = MutableStateFlow<String>("Initial")
init {
launch {
flow.debounce(30_000L).collectLatest {
ensureActive()
println(it)
}
}
}
}
}Nick Allen
06/29/2022, 6:00 PMJob in CoroutineScope, then you have to manage the coroutines individually. This is a rare but expected scenario. GlobalScope does not have a Job and can not be cancelled. To cancel collectLatest, you have to capture the Job returned by launch and cancel that.
The CoroutineScope interface docs recommend that the factory functions like CoroutineScope() are used to create an instance. You can use GlobalScope where you don't need a cancellable scope (like a process long coroutine in a singleton) and you can use CoroutineScope() or MainScope() when you do want to cancel the scope because these functions include a Job if it's not already there.
If you have a scope with the right Job (or lack of Job), then you can use + to create a new scope with the other `ContextElement`s that you want. If I wanted a non-cancellable scope for IO, I'd create it with GlobalScope + <http://Dispatchers.IO|Dispatchers.IO>.