应使用 CoroutineScope 的扩展函数或挂起函数
Should be used a CoroutineScope's extension function or a suspending function
我正在使用协程编写一个应用程序(下面的代码已大大简化)。最近我看了 Coroutines in Practice 谈话,有点困惑。原来不知道什么时候用CoroutineScope
的扩展函数,什么时候用挂起函数
我有一个实现 CoroutineScope 的 mediator (Presenter/ViewModel/Controller/etc):
class UiMediator : CoroutineScope {
private val lifecycleJob: Job = Job()
override val coroutineContext = lifecycleJob + CoroutineDispatchersProvider.MAIN
// cancel parent Job somewhere
fun getChannel() {
launch {
val channel = useCase.execute()
view.show(channel)
}
}
}
业务逻辑 (Interactor/UseCase):
class UseCase {
suspend fun execute(): RssChannel = repository.getRssChannel()
}
还有一个存储库:
class Repository {
suspend fun getRssChannel(): RssChannel {
// `getAllChannels` is a suspending fun that uses `withContext(IO)`
val channels = localStore.getAllChannels()
if (channels.isNotEmpty()) {
return channels[0]
}
// `fetchChannel` is a suspending fun that uses `suspendCancellableCoroutine`
// `saveChannel` is a suspending fun that uses `withContext(IO)`
return remoteStore.fetchChannel()
.also { localStore.saveChannel(it) }
}
}
所以我有几个问题:
- 我是否应该将
Repository#getRssChannel
声明为 CoroutineScope 的扩展函数(因为
它产生新的挂起函数:getAllChannels
,
fetchChannel
、saveChannel
)?那我怎么在UseCase
中使用呢?
- 我是否应该将
Repository#getRssChannel
包装成一个
coroutineScope
函数以使所有生成的暂停
函数是后者的 children?
- 或者它已经很好了,我什么都不应该改变。何时
那么将一个函数声明为
CoroutineScope
的扩展?
挂起函数应该 return 一旦它完成了它的任务,它就会执行一些事情,可能需要一些时间而不阻塞 UI,当它完成时 returns .
CoroutineScope 扩展函数适用于即发即弃的场景,您可以调用它,它会立即生成协程和 returns,同时任务继续执行。
问题 1 的答案:
不,你应该不声明Repository#getRssChannel
作为CoroutineScope
的扩展函数,因为你只调用挂起函数而不是启动(launch
/ async
) 新工作。正如@Francesc 解释的那样,CoroutineScope
的扩展函数应该只开始新的工作,但不能 return 立即产生结果,不应单独声明为 suspend
。
问题 2 的答案:
不,你应该不将Repository#getRssChannel
包装成CoroutineScope
。仅当您在此方法中启动 (launch
/ async
) 个新协程时,包装才有意义。新作业将是当前作业的子作业,并且外部方法只会在所有并行作业完成后 return 。在您的情况下,您有其他暂停协程的顺序调用,并且不需要新的范围。
问题 3 的答案:
是的,您可以保留您的代码。如果您需要 UiMediator#getChannel
的功能不止一次,那么此方法将成为 CoroutineScope
.
的扩展功能的候选方法
我正在使用协程编写一个应用程序(下面的代码已大大简化)。最近我看了 Coroutines in Practice 谈话,有点困惑。原来不知道什么时候用CoroutineScope
的扩展函数,什么时候用挂起函数
我有一个实现 CoroutineScope 的 mediator (Presenter/ViewModel/Controller/etc):
class UiMediator : CoroutineScope {
private val lifecycleJob: Job = Job()
override val coroutineContext = lifecycleJob + CoroutineDispatchersProvider.MAIN
// cancel parent Job somewhere
fun getChannel() {
launch {
val channel = useCase.execute()
view.show(channel)
}
}
}
业务逻辑 (Interactor/UseCase):
class UseCase {
suspend fun execute(): RssChannel = repository.getRssChannel()
}
还有一个存储库:
class Repository {
suspend fun getRssChannel(): RssChannel {
// `getAllChannels` is a suspending fun that uses `withContext(IO)`
val channels = localStore.getAllChannels()
if (channels.isNotEmpty()) {
return channels[0]
}
// `fetchChannel` is a suspending fun that uses `suspendCancellableCoroutine`
// `saveChannel` is a suspending fun that uses `withContext(IO)`
return remoteStore.fetchChannel()
.also { localStore.saveChannel(it) }
}
}
所以我有几个问题:
- 我是否应该将
Repository#getRssChannel
声明为 CoroutineScope 的扩展函数(因为 它产生新的挂起函数:getAllChannels
,fetchChannel
、saveChannel
)?那我怎么在UseCase
中使用呢? - 我是否应该将
Repository#getRssChannel
包装成一个coroutineScope
函数以使所有生成的暂停 函数是后者的 children? - 或者它已经很好了,我什么都不应该改变。何时
那么将一个函数声明为
CoroutineScope
的扩展?
挂起函数应该 return 一旦它完成了它的任务,它就会执行一些事情,可能需要一些时间而不阻塞 UI,当它完成时 returns .
CoroutineScope 扩展函数适用于即发即弃的场景,您可以调用它,它会立即生成协程和 returns,同时任务继续执行。
问题 1 的答案:
不,你应该不声明Repository#getRssChannel
作为CoroutineScope
的扩展函数,因为你只调用挂起函数而不是启动(launch
/ async
) 新工作。正如@Francesc 解释的那样,CoroutineScope
的扩展函数应该只开始新的工作,但不能 return 立即产生结果,不应单独声明为 suspend
。
问题 2 的答案:
不,你应该不将Repository#getRssChannel
包装成CoroutineScope
。仅当您在此方法中启动 (launch
/ async
) 个新协程时,包装才有意义。新作业将是当前作业的子作业,并且外部方法只会在所有并行作业完成后 return 。在您的情况下,您有其他暂停协程的顺序调用,并且不需要新的范围。
问题 3 的答案:
是的,您可以保留您的代码。如果您需要 UiMediator#getChannel
的功能不止一次,那么此方法将成为 CoroutineScope
.