英文:
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 {..}
。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论