何时使用withContext



目前我的代码看起来是这样的,我有一个ViewModel,它调用存储库进行一些后台计算并返回结果
ViewModel函数与viewModelScope.launch(Dispatchers.IO)一起运行,然后存储库函数是suspend函数
是否必须使用returnwithContext{}来确保所有操作都按顺序进行?我检查了一下,它确实是顺序的,但在文档中我发现它不一定是?

让我们先从viewModelScope的源代码中剖析它。它使用CouroutineScope的自定义实现。上下文由SupervisorJob和Dispatchers.Maindispatcher组成。这确保了协同程序在主线程上启动,并且它的失败不会影响范围内的其他协同程序。

CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))

几个值得探索的例子。

viewModelScope.launch {
Log.d("ViewModel", "Just viewModelScope: ${Thread.currentThread().name}")
}
// Output: Just viewModelScope: main
viewModelScope.launch(Dispatchers.IO) {
Log.d("ViewModel", "IO viewModelScope: ${Thread.currentThread().name}")
}
// Output: IO viewModelScope: DefaultDispatcher-worker-3
viewModelScope.launch {
Log.d("ViewModel", "viewModelScope thread: ${Thread.currentThread().name}")
withContext(Dispatchers.IO) {
delay(3000)
Log.d("ViewModel", "withContext thread: ${Thread.currentThread().name}")
}
Log.d("ViewModel", "I'm finished!")
}
// Output: 
// viewModelScope thread: main
// withContext thread: DefaultDispatcher-worker-4

我检查了一下,它确实是顺序的,但在文档中我发现它不一定是。

withContext()是一个挂起操作,协程将挂起直到完成,然后继续。从上面的第三个例子中可以明显看出这一点。

总之,viewModelScope将使用主线程来执行一个协程,该协程的取消不会影响其他协程。当您想以挂起的方式在主线程外执行繁重的任务时,请使用withContext;使用适当的调度器进行调度。Kotlin Coroutine指南值得一读。

编辑:

将以下代码视为单个执行单元。这说明了这样一个事实,即当使用withContext()时,调用线程处于挂起状态,但它没有被阻塞,这允许它继续执行并获取一些其他挂起的工作。输出记录器的交错是我们感兴趣的

viewModelScope.launch {
Log.d("ViewModel", "viewModelScope thread: ${Thread.currentThread().name}")
withContext(Dispatchers.IO) {
delay(3000)
Log.d("ViewModel", "withContext thread: ${Thread.currentThread().name}")
}
Log.d("ViewModel", "I'm finished!")
}
viewModelScope.launch {
Log.d("ViewModel", "I'm not blocked: ${Thread.currentThread().name}")
}
// Output: 
// viewModelScope thread: main
// I'm not blocked: main
// withContext thread: DefaultDispatcher-worker-2
// I'm finished!

相关内容

  • 没有找到相关文章

最新更新