如何在较低级别的管理器类中获取协程作用域

UrK*_*UrK 4 design-patterns coroutine kotlin kotlin-coroutines

我的一个库中有一个数据管理器类。到目前为止,它一直与执行者合作并拥有自己的执行者。现在该类正在转换为协程。

当管理器必须异步初始化数据时,就会出现问题,如下例所示。为了执行挂起函数,对的调用suspendedInit必须包含在launch. 这里的问题是管理器没有自己的协程作用域。

有一些我正在看但不喜欢的:

  1. 将协程作用域传递给DataManager构造函数并使用它。问题是用户DataManager尚不支持协程,因此没有自己的范围。
  2. DataManager实施CoroutineScope并创建自己的范围。正如文档所记录的那样,不鼓励这样做CoroutineScope

这个问题的推荐解决方案是什么?

    class DataManager {
        init {
            suspendedInit()
        }
        
        private suspend fun suspendedInit() = withContext(Dispatchers.IO) {
            /* some long asynchronous operations here */
        }
    }
Run Code Online (Sandbox Code Playgroud)

Jof*_*rey 5

DataManager 实现 CoroutineScope 并创建自己的作用域。CoroutineScope 文档中不鼓励这样做。

如果初始程序DataManager有自己的执行程序,那么它很可能也有自己的生命周期,并以适当的方式关闭该执行程序。

在这种情况下,完全可以按照创建CoroutineScope执行器的方式创建自己的执行器(实际上它实际上可以基于您的初始执行器)。唯一不鼓励的情况是您没有正确处理作用域的生命周期:

CoroutineScope 应声明为具有明确定义的生命周期的实体的属性,负责启动子协程。

CustomScope 自定义使用的关键部分是取消它并结束生命周期。当不再需要启动协程的实体时,应使用 CoroutineScope.cancel 扩展函数。

class DataManager {

    private val executor = TODO("original executor definition")
    val coroutineScope = executor.asCoroutineDispatcher()

    init {
        coroutineScope.launch {
            suspendedInit()
        }
    }

    private suspend fun suspendedInit() = ...

    fun close() {
        // executor.shutdown() // <-- not needed anymore
        coroutineScope.cancel()
    }
}
Run Code Online (Sandbox Code Playgroud)

如果不需要独立的线程池,您也可以完全摆脱执行器。CoroutineScope(Dispatchers.IO)在这种情况下,您可以使用(如果您想要为所有协程使用 IO 调度程序)或CoroutineScope(Dispatchers.Default)(如果您打算启动主要受 CPU 限制的任务)来初始化作用域,并withContext(IO)在必要时使用。