协程高级概念

文章目录

    • 官网地址
    • 管理长时间运行的任务
    • 使用协程确保主线程安全
        • withContext() 的效用
    • 启动协程
      • 并行分解
    • 协程概念
      • CoroutineScope
    • 作业
      • CoroutineContext

官网地址

https://developer.android.google.cn/kotlin/coroutines/coroutines-adv?hl=zh-cn

管理长时间运行的任务

协程在常规函数的基础上添加了两项操作,用于处理长时间运行的任务。在 invoke(或 call)和 return 之外,协程添加了 suspend 和 resume:

  • suspend 用于暂停执行当前协程,并保存所有局部变量。
  • resume 用于让已挂起的协程从挂起处继续执行。
suspend fun fetchDocs() {                             // Dispatchers.Main
    val result = get("https://developer.android.com") // Dispatchers.IO for `get`
    show(result)                                      // Dispatchers.Main
}

suspend fun get(url: String) = withContext(Dispatchers.IO) { /* ... */ }

使用协程确保主线程安全

Kotlin 协程使用调度程序确定哪些线程用于执行协程。要在主线程之外运行代码,可以让 Kotlin 协程在 Default 或 IO 调度程序上执行工作。在 Kotlin 中,所有协程都必须在调度程序中运行,即使它们在主线程上运行也是如此。协程可以自行挂起,而调度程序负责将其恢复。

Kotlin 提供了三个调度程序,以用于指定应在何处运行协程:

  • Dispatchers.Main - 使用此调度程序可在 Android 主线程上运行协程。此调度程序只能用于与界面交互和执行快速工作。示例包括调用 suspend 函数,运行 Android 界面框架操作,以及更新 LiveData 对象。
  • Dispatchers.IO - 此调度程序经过了专门优化,适合在主线程之外执行磁盘或网络 I/O。示例包括使用 Room 组件、从文件中读取数据或向文件中写入数据,以及运行任何网络操作。
  • Dispatchers.Default - 此调度程序经过了专门优化,适合在主线程之外执行占用大量 CPU 资源的工作。用例示例包括对列表排序和解析 JSON。
withContext() 的效用
与基于回调的等效实现相比,withContext() 不会增加额外的开销。此外,在某些情况下,还可以优化 withContext() 调用,使其超越基于回调的等效实现。例如,如果某个函数对一个网络进行十次调用,您可以使用外部 withContext() 让 Kotlin 只切换一次线程。这样,即使网络库多次使用 withContext(),它也会留在同一调度程序上,并避免切换线程。此外,Kotlin 还优化了 Dispatchers.Default 与 Dispatchers.IO 之间的切换,以尽可能避免线程切换。

启动协程

可以通过以下两种方式来启动协程:

  • launch 可启动新协程而不将结果返回给调用方。任何被视为“一劳永逸”的工作都可以使用 launch 来启动。
  • async 可启动新协程并允许您使用名为 await 的挂起函数返回结果。
    通常,您应使用 launch 从常规函数启动新协程,因为常规函数无法调用 await。只有在另一个协程内或在挂起函数内且在执行并行分解时,才使用 async。

并行分解

在 suspend 函数启动的所有协程都必须在该函数返回结果时停止,因此您可能需要保证这些协程在返回结果之前完成。借助 Kotlin 中的结构化并发机制,您可以定义用于启动一个或多个协程的 coroutineScope。然后,您可以使用 await()(针对单个协程)或 awaitAll()(针对多个协程)保证这些协程在从函数返回结果之前完成。
suspend fun fetchTwoDocs() =
    coroutineScope {
        val deferredOne = async { fetchDoc(1) }
        val deferredTwo = async { fetchDoc(2) }
        deferredOne.await()
        deferredTwo.await()
    }

协程概念

CoroutineScope

CoroutineScope 会跟踪它使用 launch 或 async 创建的任何协程。您可以随时调用 scope.cancel() 以取消正在进行的工作(即正在运行的协程)。在 Android 中,某些 KTX 库为某些生命周期类提供自己的 CoroutineScope。例如,ViewModel 有 viewModelScope,Lifecycle 有 lifecycleScope。不过,与调度程序不同,CoroutineScope 不运行协程。

class ExampleClass {

    // Job and Dispatcher are combined into a CoroutineContext which
    // will be discussed shortly
    val scope = CoroutineScope(Job() + Dispatchers.Main)

    fun exampleMethod() {
        // Starts a new coroutine within the scope
        scope.launch {
            // New coroutine that can call suspend functions
            fetchDocs()
        }
    }

    fun cleanUp() {
        // Cancel the scope to cancel ongoing coroutines work
        scope.cancel()
    }
}

作业

Job 是协程的句柄。使用 launch 或 async 创建的每个协程都会返回一个 Job 实例,该实例是相应协程的唯一标识并管理其生命周期。您还可以将 Job 传递给 CoroutineScope 以进一步管理其生命周期,如以下示例所示

class ExampleClass {
    ...
    fun exampleMethod() {
        // Handle to the coroutine, you can control its lifecycle
        val job = scope.launch {
            // New coroutine
        }

        if (...) {
            // Cancel the coroutine started above, this doesn't affect the scope
            // this coroutine was launched in
            job.cancel()
        }
    }
}

CoroutineContext

CoroutineContext 使用以下元素集定义协程的行为:

  • Job:控制协程的生命周期。
  • CoroutineDispatcher:将工作分派到适当的线程。
  • CoroutineName:协程的名称,可用于调试。
  • CoroutineExceptionHandler:处理未捕获的异常。
class ExampleClass {
    val scope = CoroutineScope(Job() + Dispatchers.Main)

    fun exampleMethod() {
        // Starts a new coroutine on Dispatchers.Main as it's the scope's default
        val job1 = scope.launch {
            // New coroutine with CoroutineName = "coroutine" (default)
        }

        // Starts a new coroutine on Dispatchers.Default
        val job2 = scope.launch(Dispatchers.Default + CoroutineName("BackgroundCoroutine")) {
            // New coroutine with CoroutineName = "BackgroundCoroutine" (overridden)
        }
    }
}

你可能感兴趣的:(Kotlin,Android,Kotlin,协程,协程高级概念,CoroutineScope,启动协程,协程确保主线程安全)