创建自己的挂起 API
之前我们提到 Jetbrains 为 Coroutines API 考虑的一件事是可扩展性。在前面的章节您已经看到如何把自己的函数转换为可挂起的,现在您可以做的另外一件事就是创建一些类似 API 的实用功能,它们可以隐藏线程和上下文切换逻辑。
我们在 Api.kt 中为您准备了一些示例。打开它您将看到一些函数,我们将逐一介绍它们。
第一个是一个比较方便的函数,它使用 suspendCoroutine
和 Result's runCatching
来尝试处理一个数据,并最后返回给您。
suspend fun <T : Any> getValue(provider: () -> T): T =
suspendCoroutine { continuation ->
continuation.resumeWith(Result.runCatching { provider() })
}
如果您要在代码中的某处调用此函数,它会看起来像下面这样:
GlobalScope.launch {
val user = getValue { getUserFromNetwork("101") }
println(user)
}
这可以帮助您抽象出所有尝试通过以下方式获取数据的逻辑:
- 网络访问,
- 文件读取,
- 数据库查找等。
并将它们切换至后台线程执行。如此主线程只需处理渲染数据,其余代码仅仅获取渲染数据即可。
下面两个示例非常简单,但它们对线程切换非常有用:
fun executeBackground(action: suspend () -> Unit) {
GlobalScope.launch { action() }
}
fun executeMain(action: suspend () -> Unit) {
GlobalScope.launch(context = Dispatchers.Main) { action() }
}
第一个函数需要传入一个 action
lambda 代码块,并且使用 launch
默认的上下文将它运行在后台线程。第二个函数同样需要传入 action
lambda 代码块,但是它使用 Dispatchers.Main
上下文,所以您可以轻松的切换到主线程,并且不知道任何实现细节。
您可能会像下面这样使用它们:
executeBackground {
val user = getValue { getUserFromNetwork("101") }
executeMain { println(user) }
}
上述方法的命名是一个很好的例子,您可以理解它背后的意图。现在您拥有和 GlobalScope.launch
代码块相关的行为,但是您不必了解在这背后使用了哪个作用域以及哪个函数。
这在您构建基础业务逻辑层时非常有用,因为您可以提供主线程上下文和后台线程上下文以及运行函数的范围。并且在具体的实现,或者 base presenter
的子类,view model
或 controller
中,您只需调用这些函数,然后让该层的核心部分去处理线程。
根据您的需要,尽可能多的使用它们并在它们之上构建更多实用功能。