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>
.