这个 Kotlin CoroutineScope 与 Dispatcher 和 CoroutineContext 之间的关系是什么?

huangapple go评论64阅读模式
英文:

What's the relationship between this Kotlin CoroutineScope and Dispatcher and CoroutineContext

问题

如附图所示,代码(来自这里的Kodeco)位于Android Fragment中,我想知道Dispatchers.Main在这两行之间的关系:

L63: private val coroutineScope = CoroutineScope(Dispatchers.Main + parentJob)
L68: coroutineScope.launch(Dispatchers.Main) { .. }

根据我的理解,L63上的Dispatchers.Main表示coroutineScope绑定到主线程,而L68上的Dispatchers.Main表示coroutine块将在主线程中运行。

但我是否需要两次指定它?如果我不这样做会发生什么,例如,如果我将L68更改为以下方式:coroutineScope.launch {..}

英文:

这个 Kotlin CoroutineScope 与 Dispatcher 和 CoroutineContext 之间的关系是什么?

As attached, the code (from Kodeco at here) is in an Android Fragment, I was wondering what's the relationship of Dispatchers.Main between these two lines:

L63: private val coroutineScope = CoroutineScope(Dispatchers.Main + parentJob)
L68: coroutineScope.launch(Dispatchers.Main) { .. }

What by my understanding is, the Dispatchers.Main on L63 means the coroutineScope is bound to Main thread, and the Dispatchers.Main on L68 means the coroutine block will be run in Main thread.

But do I have to specify it twice? What if I don't do like this, for example, what happens if I change L68 to be like: coroutineScope.launch {..}

答案1

得分: 1

抱歉,这是一个愚蠢的问题,我现在明白了,就像下面这样:

L63: private val coroutineScope = CoroutineScope(Dispatchers.Main + parentJob)

这指定了一个自定义的协程范围,这个范围已经绑定到Dispatchers.Main(主线程),让我们在这个问题中忽略parentJob。

“已绑定到Dispatchers.Main”意味着:由此范围启动的协程将在主线程中运行。

而在L68:

L68: coroutineScope.launch(Dispatchers.Main) { .. }

这再次指定,协程块将在主线程中运行。
所以,关于这里的“再次”,我是说,通过查看launch函数的源代码,我找到了这个:

val newContext = newCoroutineContext(context)

newCoroutineContext(context)函数中有一个上下文组合,看起来像这样:

val combined = coroutineContext + context

这意味着将L68的Dispatchers.Main添加到L63的Dispatchers.Main,因为它们是相同的,所以最终在L68之后的协程块将一直在主线程中运行。

所以,来回答我的问题:如果我将L68更改为以下形式会发生什么:coroutineScope.launch {..},没有什么会改变,一切都完全相同,因为在之前和之后,协程块将一直在主线程中运行。

但是,如果我们将L68更改为以下形式:

coroutineScope.launch(Dispatchers.IO) { .. }

嗯,这一次应用程序将崩溃,因为它试图从工作线程更新UI:

E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-4
    Process: com.raywenderlich.snowy, PID: 8562
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

这是因为L68的Dispatchers.IO覆盖了L63的Main。

只需将问题和我的帖子保留一会儿,以防它能帮助像我一样对此感到困惑的人。

英文:

Sorry for this dumb question, I got it now like below:

L63: private val coroutineScope = CoroutineScope(Dispatchers.Main + parentJob)

This specifies a custom coroutine scope, and this scope has been bound to the Dispatchers.Main (the main thread, and let's ignore parentJob in this question).

has bound to Dispatchers.Main means: the coroutine started by this scope will run in main thread.

And on L68:

L68: coroutineScope.launch(Dispatchers.Main) { .. }

this specifies, again, the coroutine block will run in main thread.
So as for the again here, I mean, by looking into the source code of launch function, I found this:

val newContext = newCoroutineContext(context)

And there is a context combination in the function of newCoroutineContext(context) which looks like:

val combined = coroutineContext + context

which means add the L68's Dispatchers.Main onto the L63's Dispatchers.Main, owing to they are the same, so finally the coroutine block after L68 will run in the main thread.

So to answer my question: what happens if I change L68 to be like: coroutineScope.launch {..}, nothing will change, everything is exactly the same, since before and after, the coroutine block will run on main thread consistently.

But, what if we change the L68 like:

coroutineScope.launch(Dispatchers.IO) { .. }

Well, this time, the app will crash because of it's trying to update the UI from a worker thread:

E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-4
    Process: com.raywenderlich.snowy, PID: 8562
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

This is because, the L68's Dispatchers.IO overrode the L63's Main.

Just keep the question and my post for a while here, in case it could help someone like me had the same confuse.

huangapple
  • 本文由 发表于 2023年1月9日 10:43:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/75052745.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定