什么时候使用withContext?

问题描述 投票:0回答:1

目前我的代码如下所示:

我有一个

ViewModel
,它调用存储库来执行一些后台计算并返回结果。

ViewModel 函数使用

viewModelScope.launch(Dispatchers.IO)
运行,然后存储库是一个
suspend
函数。

我是否必须使用 return

withContext {}
来确保一切都会按顺序完成?我查了一下,确实是顺序的,但是在文档中我发现它不一定是顺序的?

android kotlin kotlin-coroutines coroutine android-viewmodel
1个回答
20
投票

让我们首先从源代码中剖析

viewModelScope
。它使用
CouroutineScope
的自定义实现。上下文由 SupervisorJobDispatchers.Main 调度程序组成。这确保了协程在主线程上启动,并且它的失败不会影响范围内的其他协程。

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 guide 值得一读。

编辑:

将以下代码视为单个执行单元。这说明了这样一个事实:当使用

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!
© www.soinside.com 2019 - 2024. All rights reserved.