1. CoroutineScope

CoroutineScope 是协程生命周期的管理者,它可以追踪你通过 launchasync 启动的协程(这两个函数是 CoroutineScope 的扩展函数)。你可以通过调用 scope.cancel() 来取消当前的协程。在 Android 中,KTX 库为你提供了可以感知生命周期的 CoroutineScope,如 viewModelScopelifecycleScope,它们会在适当的时候自动取消协程。

创建一个 CoroutineScope 时,需要一个 CoroutineContext 作为其构造函数的参数:

// Job 和 Dispatcher 组合成 CoroutineContext
val scope = CoroutineScope(Job() + Dispatchers.Main)

val job = scope.launch {
    // 启动新的协程
}

在这个例子中,CoroutineScope 包含了 Job()Dispatchers.Main,确保协程在主线程中执行并且具有生命周期管理。

2. Job

Job 是协程的句柄。每个通过 launchasync 启动的协程都会返回一个 Job 实例,它是协程的唯一标识符,并且可以用来管理协程的生命周期。通过 Job,你可以控制协程的取消、监控其完成状态等。

例如:

val job = scope.launch {
    // 启动的协程
}

每个协程都关联一个 Job,该 Job 的生命周期与协程的生命周期同步。你可以通过调用 job.cancel() 来取消协程,或者使用 job.isActive 等属性来检查协程的状态。

3. CoroutineContext

CoroutineContext 是协程的上下文,它定义了协程的行为。一个 CoroutineContext 由多个元素组成:

  • Job: 控制协程的生命周期。
  • CoroutineDispatcher: 确定协程执行在哪个线程上。
  • CoroutineName: 协程的名称,通常用于调试。
  • CoroutineExceptionHandler: 处理未捕获的异常。

当创建一个协程时,它会有一个新的 Job 实例,该实例可以控制协程的生命周期。其他的元素(如调度器、异常处理器等)会从父级的 CoroutineContext 中继承。

val scope = CoroutineScope(Job() + Dispatchers.Main)
scope.launch {
    // 新的协程,它的父级是 CoroutineScope
    val result = async {
        // 新的协程,它的父级是 launch
    }.await()
}

在这个例子中,协程有一个父级 CoroutineContext,可以是 CoroutineScope 或另一个协程。创建的每个新协程都将继承父级的 CoroutineContext

4. Job的生命周期

Job 的生命周期经历多个状态:

  • New: 协程被创建但未启动。
  • Active: 协程正在运行。
  • Completing: 协程正在结束。
  • Completed: 协程已完成。
  • Cancelling: 协程正在被取消。
  • Cancelled: 协程已取消。

尽管我们无法直接访问这些状态,但可以通过 Job 的一些属性来判断协程的状态:

  • isActive: 判断协程是否处于激活状态。
  • isCancelled: 判断协程是否被取消。
  • isCompleted: 判断协程是否完成。

例如,如果协程处于 Active 状态,执行失败或调用 job.cancel() 会将 Job 转为 Cancelling 状态。

5. 父级CoroutineContext

每个协程都有一个父级上下文,父级可以是 CoroutineScope 或另一个协程。然而,一个协程的 CoroutineContext 可以与父级的 CoroutineContext 不同。父级的 CoroutineContext 是基于以下公式计算的:

Parent context = Defaults + inherited CoroutineContext + arguments
  • Defaults: 默认值,如 Dispatchers.DefaultCoroutineDispatcher 的默认值。
  • Inherited CoroutineContext: 父级 CoroutineContext(即创建该协程的 CoroutineScope 或协程的 CoroutineContext)。
  • Arguments: 传递给协程构造器的参数优先于继承的元素。

例如:

val scope = CoroutineScope(Job() + Dispatchers.Main + coroutineExceptionHandler)

父级 CoroutineContext 将包含 Dispatchers.Main、默认的 "coroutine" 名称、Job 和异常处理器。

对于新创建的协程来说,它的 CoroutineContext 会是:

New coroutine context = parent CoroutineContext + Job()

例如:

val job = scope.launch(Dispatchers.IO) {
    // 新的协程
}

在这个例子中,父级 CoroutineContext 中的 DispatchersDispatchers.IO 而不是 Dispatchers.Main,因为它是通过协程构造器传递的参数来覆盖的。

6. 小结

本文介绍了协程的一些核心概念:CoroutineScopeJobCoroutineContext。这些概念对于理解协程的生命周期和如何管理协程至关重要。

  • CoroutineScope 用于创建协程,并跟踪其生命周期。
  • Job 是协程的句柄,提供了管理协程生命周期的能力。
  • CoroutineContext 是协程的上下文,定义了协程的行为,包括调度器、异常处理等。

🌟 关注我的CSDN博客,收获更多技术干货! 🌟

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐