android - Kotlin 中 coroutineScope 的生命周期是多少?
问题描述
代码 A 来自https://github.com/android/architecture-samples上的项目架构示例
1:我不知道函数activateTask(task: Task)
是否需要runBlocking
像代码B一样包装。如果对象被快速销毁,恐怕activateTask(task: Task)
可能无法运行DefaultTasksRepository
。
2:正常运行协程ViewModel.viewModelScope
,不知道ViewModel.viewModelScope
app完成后会不会被销毁,运行的协程是否ViewModel.viewModelScope
也会被销毁。如果是这样,我认为会很糟糕,一些长时间的协程,例如向远程服务器写入数据将被取消。
3:还有,activateTask
代码A中的函数是协程函数,可以直接调用另一个协程函数,所以我认为代码A+是正确的,对吧?
代码 A
import kotlinx.coroutines.coroutineScope
...
class DefaultTasksRepository(
private val tasksRemoteDataSource: TasksDataSource,
private val tasksLocalDataSource: TasksDataSource,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : TasksRepository {
...
override suspend fun activateTask(task: Task) = withContext<Unit>(ioDispatcher) {
coroutineScope {
launch { tasksRemoteDataSource.activateTask(task) }
launch { tasksLocalDataSource.activateTask(task) }
}
}
override suspend fun clearCompletedTasks() {
coroutineScope {
launch { tasksRemoteDataSource.clearCompletedTasks() }
launch { tasksLocalDataSource.clearCompletedTasks() }
}
}
...
}
代码 A+
import kotlinx.coroutines.coroutineScope
...
class DefaultTasksRepository(
private val tasksRemoteDataSource: TasksDataSource,
private val tasksLocalDataSource: TasksDataSource,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) : TasksRepository {
...
override suspend fun activateTask(task: Task) = withContext<Unit>(ioDispatcher) {
tasksRemoteDataSource.activateTask(task)
tasksLocalDataSource.activateTask(task)
}
override suspend fun clearCompletedTasks() {
tasksRemoteDataSource.clearCompletedTasks()
tasksLocalDataSource.clearCompletedTasks()
}
...
}
代码 B
fun main() = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
解决方案
您不应该在任何协程应用程序中使用 runBlocking,它会阻塞线程。
如果您真的想使
activateTask
不可取消,那么标准库中已经有NonCancellable的工厂实现并且您不应该在 withContext 中使用 coroutineScope 包装器,因为新创建的 CoroutineScope 和新作业已经作为接收器在
withContext
.像这样实现您的 activateTask:
override suspend fun activateTask(task: Task) = withContext<Unit>(ioDispatcher + NonCancellable) {
launch { tasksRemoteDataSource.activateTask(task) }
launch { tasksLocalDataSource.activateTask(task) }
}
通过这种方式,它将在 IODispatcher 上调用,但不可取消,因为Job
结果上下文的元素不提供取消它的功能。
ViewModelScope 一直运行到您的应用程序被销毁,更多信息和生命周期图表在这里。如果您想运行一些非常重要的任务,请使用其他调度程序。
是的,代码 A+ 完全正确
PS:你不应该在协程应用程序中实现runBlocking,它的默认实现只是事件循环。
runBlocking 是桥接同步和异步代码的方式
更好的 main 函数实现应该是:
suspend fun main() = coroutineScope {
// code here
}
它在 CommonPool 上运行,如果它挂起另一个协程可以重用同一个线程。
推荐阅读
- node.js - AWS Elastic Beanstalk | 错误:无法运行 npm 安装。快照日志以获取更多详细信息
- c# - C# 中的动态浮点格式化程序
- c# - 没有可用的测试..通过 exe 在 VM 上使用构建工具和测试代理进行测试
- python - 播放带有 winsound 问题的随机 wav 文件
- html - 媒体查询无法在 Opera mini 浏览器上运行,但在 Firefox 和 chrome 浏览器上运行良好
- azure - 是否可以使用 onPremisesSyncEnabled(Microsoft Graph API)来监视 Azure AD 是否同步?
- node.js - 为什么会出现“0 - 未知错误 [object ProgressEvent]”错误?
- c# - 按组在单独的线程中运行处理
- git - 在 Git 中为多个推送提交只创建一个提交
- r - 使用循环导入许多文件