若要更改函数中的线程,请使用CoroutineScope或withContext。我不知道有什么区别,但是对于CourineScope,我也可以使用一个处理程序。
示例:
private fun removeViews(){
CoroutineScope(Main).launch(handler){
gridRoot.removeAllViews()
}
}
private suspend fun removeViews(){
withContext(Main){
gridRoot.removeAllViews()
}
}我从在后台线程(IO)上工作的协同线调用这个函数。比其他人更合适吗?
发布于 2020-09-17 09:17:31
这两者实际上是完全不同的,您只是碰巧有一个没有体验到差别的用例:
CoroutineScope(Main).launch(handler){
这就启动了一个独立进行的并行协同机制。
withContext(Main){
这是一个只有在代码完成并返回其结果时才能完成的函数。你应该这么做的。
使用CoroutineScope的第一种方法还有另一个缺点,就是它绕过了结构化并发。您创建了一个没有父级的临时协同作用域,因此,如果需要更长的时间来完成并且您的GUI被删除,就不会自动清除它(用户导航远离当前的活动)。
实际上,您不应该使用CoroutineScope(Main)成语,我认为没有一个实例是合适的。如果您明确地希望避免结构化并发,那么编写它还是更好、更干净。
GlobalScope.launch(Main + handler) {也有同样的效果。
如果您想要一个符合结构化并发的并发协同机制,请使用
fun CoroutineScope.removeViews() {
launch {
gridRoot.removeAllViews()
}
}注意,我删除了handler参数,一个子协同器忽略它,因为它将所有故障转发给其父协同器,这正是您想要的。父协同应安装一个异常处理程序。
发布于 2020-09-15 15:20:59
在技术上两者是相同的,但是在用例方面两者是不同的,并且对不同的用例有很大的影响,所以在使用它们时要小心。
合作范围:
CoroutineScope是Coroutine的起点。CoroutineScope的内部可以有多个协同线,这就构成了协同线层次结构。让我们想想,父母有不止一个孩子。假设CoroutineScope是一个父母,并且这个父母可以有多个孩子,这也是合作关系。这些孩子被称为job
private val coroutineScope = CoroutineScope()
coroutineScope(IO).launch{
val childOne = launch(Main){}
val childTwo = launch(Main){}
}看到那个childOne和childTwo了吗?为什么我们需要这些?因为我们不能直接取消协同线,所以没有这样的方法可以直接取消协同线,要么coroutine完成,要么失败。但如果我们想取消呢?在这种情况下,我们需要job。但在这里值得注意的是,这些工作children与家长完全相关。而父母是( IO )和子女是(Main),这个父母是在IO Disptacher中启动的,但是当涉及到他们将要切换到(Main)并做他们的事情的那些孩子时,家长仍然在(IO)切换孩子的调度员不会影响家长。
但是,如果其中任何一个孩子出了什么差错,我们就会看到这次峰会:
https://www.youtube.com/watch?v=w0kfnydnFWI
这次峰会是关于合作异常和取消的。看着它,这太神奇了..。
withContext:
withContext是什么?
withContext应该在任何Coroutine或suspend fun中,因为withContext本身是一个挂起函数。
withContext用于在不同情况下切换上下文
但是怎么做呢?
suspend fun fetchFromNetworkAndUpdateUI() {
withContext(IO){
println("Some Fake data from network")
}
withContext(Main){
//updating Ui
//setting that Data to some TextView etc
}
}查看代码,我们从网络中异步获取数据,因为我们不想阻止MainThread,然后切换上下文,为什么?因为我们不能更新IoDispatcher中与UI相关的内容,也就是说,我们必须用withContext(main){}将上下文更改为main,并更新UI。
还有其他一些用例,比如liveData,我们使用IoDispatcher进行改造来获取值,接下来我们必须使用withContext(main){}将其设置为liveData,因为我们不能在后台线程中观察liveData的值。
是啊,我希望这能帮上忙。如果有任何问题,请发表评论。
发布于 2020-09-16 09:28:58
来自安东尼奥·莱瓦文章关于协同服务的文章:
coroutine上下文是一组规则和配置,这些规则和配置定义了如何执行协同线。
withContext是一个函数,它允许您轻松地更改挂起函数的context,以确保该函数在特定线程(例如IO池中的线程)中执行。为此,可以强制挂起函数在特定线程池中执行其主体,例如:
suspend fun getAuthenticationStatus(): AuthenticationStatus = withContext(Dispatchers.IO) {
when (val result = repository.getAuthenticationStatus()) {
is Result.Success -> result.data
is Result.Error -> AuthenticationStatus.Unauthorized
}
}这样,即使从UI作用域(MainScope)调用此挂起函数,也可以100%确定挂起函数是在工作线程中执行的,并且可以在主线程中使用返回的结果更新UI,例如:
MainScope().launch {
userIdentityVM.getAuthenticationStatus().run {
when (this) {
is AuthenticationStatus.Authenticated -> {
// do something
}
is AuthenticationStatus.Unauthorized -> {
// do something else
}
}
}
}总之,通过使用withContext,您可以使挂起的函数“主安全”。
scope和context之间的区别基本上是预期的目的。要启动coroutine,通常使用launch协同构建器,定义为CoroutineScope上的扩展函数。
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
// ...
): Jobcoroutine作用域上指定为参数的上下文被加号运算符合并为coroutine作用域,在coroutine作用域指定的“默认”上下文中优先使用。这样,您就可以在“父”上下文中执行代码。为了深入研究,我建议您使用Roman ( Kotlin @JetBrains的团队负责人)编写的这篇文章。
https://stackoverflow.com/questions/63902953
复制相似问题