在 Google Codelab for Coroutines 中,我们看到了一个MainCoroutineScopeRule
。在该规则中,它解释了除了Dispatchers.Main
之外,此规则还可以扩展到其他调度程序:
override fun starting(description: Description?) {
super.starting(description)
// If your codebase allows the injection of other dispatchers like
// Dispatchers.Default and Dispatchers.IO, consider injecting all of them here
// and renaming this class to `CoroutineScopeRule`
//
// All injected dispatchers in a test should point to a single instance of
// TestCoroutineDispatcher.
Dispatchers.setMain(dispatcher)
}
我的问题是,我们究竟如何注入其他调度员?这是否假设我们正在使用依赖注入?如果是这样,如果我不使用 DI,我是否仍可以将此规则扩展到其他调度程序?我在 kotlinx-coroutines-test 库中没有看到任何允许我将TestCoroutineDispatcher
设置为其他调度程序的内容。所以,有这个:
Dispatchers.setMain(dispatcher)
。但不是这个:
Dispatchers.setIO(dispatcher) // Or Default, etc.
我是否应该重写我的suspend
函数以将调度程序作为参数:
suspend doSomeIO(dispatcher: CoroutineDispatcher = Dispatchers.IO) {
launch(dispatcher) {
// Some long-running IO operation
}
}
您是正确的,因为这确实假设您正在注入调度程序。 如果不使用主调度程序,则应注入调度程序以正确测试它。
编写挂起函数的方式是一种方法,如果要强制该特定函数位于 Dispatchers.IO 线程上。 但是,您最终将拥有嵌套启动。
取而代之的是,我只是将调度程序传递给视图模型,并让视图模型决定如何调用挂起函数。
//Your version:
suspend fun doSomeIO(dispatcher: CoroutineDispatcher = Dispatchers.IO) {
launch(dispatcher) {
// Some long-running IO operation
}
}
class MyViewModel(val dispatcher: CoroutineDispatcher = Dispatchers.IO: ViewModel() {
init {
viewModelScope.launch {
doSomeIO(dispatcher) // here you are launching one coroutine inside the other
}
}
}
// Instead try this:
suspend fun doSomeIO() {
// Some long-running IO operation
}
class MyViewModel(val dispatcher: CoroutineDispatcher = Dispatchers.IO: ViewModel() {
init {
viewModelScope.launch(dispatcher) {
doSomeIO()
}
}
}