英文:
Why don't I use viewModelScope(Dispatchers.IO).launch{ } with Kotlin?
问题
Code A是正确的,所以我认为Code B也是正确的,但实际上Code C可以编译,为什么?
Code B有什么问题?
Code A
CoroutineScope(Dispatchers.IO).launch {
}
Code B
viewModelScope(Dispatchers.IO).launch{
}
Code C
viewModelScope.launch(Dispatchers.IO){
}
英文:
The Code A is Ok, so I think Code B is Ok too, but in fact Code C can be compiled, why ?
What's wrong with Code B ?
Code A
CoroutineScope(Dispatchers.IO).launch {
}
Code B
viewModelScope(Dispatchers.IO).launch{
}
Code C
viewModelScope.launch(Dispatchers.IO){
}
答案1
得分: 2
很简单,CoroutineScope
和 launch
是函数,viewModelScope
是属性。
CoroutineScope()
是一个函数,它接受一个 CoroutineContext 参数,用于启动它的作业。launch
是一个函数,它接受一个可选的 CoroutineContext 参数,它将与其作用域的上下文合并,用于在其自己的协程中使用。viewModelScope
是一个 CoroutineScope 的实例。它不是一个可调用的函数。
英文:
It’s as simple as CoroutineScope
and launch
are functions, and viewModelScope
is a property.
CoroutineScope()
is a function that takes a CoroutineContext parameter that it will use for jobs that it launches.launch
is a function that takes an optional CoroutineContext parameter that it will merge with its scope’s context to use in its own coroutine.viewModelScope
is an instance of a CoroutineScope. It is not an invokeable function.
答案2
得分: 1
Code A ✅
Code B ❌
Code C ✅
解释
Code A
CoroutineScope(Dispatchers.IO).launch {
}
它有效,因为它创建了一个新的CoroutineScope
,使用Dispatchers.IO
并在该作用域中使用launch
函数启动一个协程。
Code B
viewModelScope(Dispatchers.IO).launch{
}
它不起作用,因为viewModelScope
是返回与ViewModel
的生命周期绑定的CoroutineScope
的属性。但是launch
函数不是CoroutineScope
类的成员,因此不能直接从viewModelScope
中调用。
Code C
viewModelScope.launch(Dispatchers.IO){
}
它有效,因为viewModelScope
是返回与ViewModel
的生命周期绑定的CoroutineScope
的属性。在这段代码中,launch
函数是在由该属性返回的viewModelScope
对象上调用的,并将Dispatchers.IO
调度程序作为参数传递给launch
函数。
希望现在清楚了。
英文:
Code A ✅
Code B ❌
Code C ✅
Explanation
Code A
CoroutineScope(Dispatchers.IO).launch {
}
It works because it creates a new CoroutineScope
with the Dispatchers.IO
and launches a coroutine in that scope using the launch
function.
Code B
viewModelScope(Dispatchers.IO).launch{
}
It does not work because viewModelScope
is a property that returns a CoroutineScope
tied to the lifecycle of the ViewModel
. However the launch
function is not a member of the CoroutineScope
class, so it can not be called from viewModelScope
directly.
Source code
Code C
viewModelScope.launch(Dispatchers.IO){
}
It does work because viewModelScope
is a property that returns a CoroutineScope
tied to the lifecycle of the ViewModel
. In this code, the launch function is called on the viewModelScope
object returned by the property, and the Dispatchers.IO
dispatcher is passed as a parameter to the launch
function.
Source code
Hope it's clear now.
答案3
得分: 1
In Code A,您正在使用CoroutineScope
Builder创建自己的协程,通过提供Dispatcher
,这是可以的,因为它允许您创建自己的协程。
In Code B,您正在使用viewModelScope
,这是一个扩展属性,不像CoroutineScope
或GlobalScope
那样是协程构建器,正如下面的源代码所示。
get() {
val scope: CoroutineScope? = this.getTag(JOB_KEY)
if (scope != null) {
return scope
}
return setTagIfAbsent(
JOB_KEY,
CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
)
}
In Code C,您正在使用launch
,这是CoroutineScope
的扩展函数,根据源代码接受参数。
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}
英文:
In Code A , You are creating you own coroutine using CoroutineScope
Builder by giving Dispatcher
so that's fine as it allows you to create it your own
In Code B , you are using viewModelScope which is extension property not (not accepting any arguments) coroutine builder like CoroutineScope
or GlobalScope
as you can see it's source code as mentioned below
public val ViewModel.viewModelScope: CoroutineScope
get() {
val scope: CoroutineScope? = this.getTag(JOB_KEY)
if (scope != null) {
return scope
}
return setTagIfAbsent(
JOB_KEY,
CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
)
}
In Code C , you are using launch
which is extension function of CoroutineScope
and accepting arguments as mentioned in source code
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论