应使用 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) }
    }
}

所以我有几个问题:

  1. 我是否应该将 Repository#getRssChannel 声明为 CoroutineScope 的扩展函数(因为 它产生新的挂起函数:getAllChannelsfetchChannelsaveChannel)?那我怎么在UseCase中使用呢?
  2. 我是否应该将 Repository#getRssChannel 包装成一个 coroutineScope 函数以使所有生成的暂停 函数是后者的 children?
  3. 或者它已经很好了,我什么都不应该改变。何时 那么将一个函数声明为 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.

的扩展功能的候选方法