英文:
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.launchis a function that takes an optional CoroutineContext parameter that it will merge with its scope’s context to use in its own coroutine.viewModelScopeis 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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。





评论