协程嵌套协程_协程首先要做的事

本文深入介绍了协程中的取消和异常处理,强调了它们在优化资源使用和提供良好用户体验中的重要性。CoroutineScope用于跟踪和控制协程生命周期,可以使用Job来取消协程。CoroutineContext定义了协程的行为,包括Job、Dispatcher和其他元素。协程在任务层级中执行,子协程可以从父CoroutineScope或另一协程继承CoroutineContext。理解这些核心概念对于有效管理协程至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

协程嵌套协程

重点 (Top highlight)

This series of blog posts goes in-depth into cancellation and exceptions in Coroutines. Cancellation is important for avoiding doing more work than needed which can waste memory and battery life; proper exception handling is key to a great user experience. As the foundation for the other 2 parts of the series (part 2: cancellation, part 3: exceptions), it’s important to define some core coroutine concepts such as CoroutineScope, Job and CoroutineContext so that we all are on the same page.

该系列博客文章深入探讨了协程中的取消和异常。 取消对于避免做过多的工作很重要,因为这可能会浪费内存和电池寿命。 正确的异常处理是获得良好用户体验的关键。 作为本系列其他两个部分( 第2部分:取消第3部分:异常 )的基础,定义一些核心的协程概念(如CoroutineScopeJobCoroutineContext非常重要,这样我们才能在同一页面上。

If you prefer video, check out this talk from KotlinConf’19 by Florina Muntenescu and I:

如果您喜欢视频,请查看Florina Muntenescu和我在KotlinConf'19上的演讲

协同范围 (CoroutineScope)

A CoroutineScope keeps track of any coroutine you create using launch or async (these are extension functions on CoroutineScope). The ongoing work (running coroutines) can be canceled by calling scope.cancel() at any point in time.

CoroutineScope会跟踪您使用launchasync创建的任何协程(这些是CoroutineScope上的扩展功能)。 可以通过在任何时间点调用scope.cancel()来取消正在进行的工作(正在运行的协程)。

You should create a CoroutineScope whenever you want to start and control the lifecycle of coroutines in a particular layer of your app. In some platforms like Android, there are KTX libraries that already provide a CoroutineScope in certain lifecycle classes such as viewModelScope and lifecycleScope.

每当您要启动和控制应用程序特定层中协程的生命周期时,都应创建一个CoroutineScope 。 在某些平台(如Android)中,已经有KTX库在某些生命周期类(例如viewModelScopelifecycleScope提供了CoroutineScope

When creating a CoroutineScope it takes a CoroutineContext as a parameter to its constructor. You can create a new scope & coroutine with the following code:

创建CoroutineScope ,它将CoroutineContext作为其构造函数的参数。 您可以使用以下代码创建新的合并范围和协程:

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

工作 (Job)

A Job is a handle to a coroutine. For every coroutine that you create (by launch or async), it returns a Job instance that uniquely identifies the coroutine and manages its lifecycle. As we saw above, you can also pass a Job to a CoroutineScope to keep a handle on its lifecycle.

Job是协程的句柄。 对于您创建的每个协程(通过launchasync ),它将返回一个Job实例,该实例唯一地标识协程并管理其生命周期。 正如我们在上面看到的,您还可以将Job传递给CoroutineScope以保持其生命周期。

协程上下文 (CoroutineContext)

The CoroutineContext is a set of elements that define the behavior of a coroutine. It’s made of:

CoroutineContext 是定义协程行为的一组元素。 它是由:

What’s the CoroutineContext of a new coroutine? We already know that a new instance of Job will be created, allowing us to control its lifecycle. The rest of the elements will be inherited from the CoroutineContext of its parent (either another coroutine or the CoroutineScope where it was created).

什么是新的协程的协程CoroutineContext ? 我们已经知道将创建一个新的Job实例,从而使我们能够控制其生命周期。 其余元素将从其父级的CoroutineContext (另一个协程或在其创建的CoroutineScope中继承。

Since a CoroutineScope can create coroutines and you can create more coroutines inside a coroutine, an implicit task hierarchy is created. In the following code snippet, apart from creating a new coroutine using the CoroutineScope, see how you can create more coroutines inside a coroutine:

由于CoroutineScope可以创建协程,并且您可以在协程内部创建更多协程,因此将创建隐式任务层次结构 。 在以下代码片段中,除了使用CoroutineScope创建新的协程CoroutineScope ,还请参见如何在协程内部创建更多协程:

val scope = CoroutineScope(Job() + Dispatchers.Main)val job = scope.launch {
// New coroutine that has CoroutineScope as a parent
val result = async {
// New coroutine that has the coroutine started by
// launch as a parent
}.await()
}

The root of that hierarchy is usually the CoroutineScope. We could visualise that hierarchy as follows:

该层次结构的根通常是CoroutineScope 。 我们可以将该层次结构可视化如下:

Image for post
Coroutines are executed in a task hierarchy. The parent can be either a CoroutineScope or another coroutine.
协程在任务层次结构中执行。 父级可以是CoroutineScope或另一个协程。

工作生命周期 (Job lifecycle)

A Job can go through a set of states: New, Active, Completing, Completed, Cancelling and Cancelled. While we don’t have access to the states themselves, we can access properties of a Job: isActive, isCancelled and isCompleted.

Job可以经历以下一组状态:新建,活动,正在完成,已完成,正在取消和已取消。 尽管我们无权访问状态本身,但我们可以访问Job的属性: isActiveisCancelledisCompleted

Image for post
Job lifecycle
工作生命周期

If the coroutine is in an active state, the failure of the coroutine or calling job.cancel() will move the job in the Cancelling state (isActive = false, isCancelled = true). Once all children have completed their work the coroutine will go in the Cancelled state and isCompleted = true.

如果协程处于活动状态,则协程失败或调用job.cancel()将使作业处于取消状态( isActive = falseisCancelled = true )。 一旦所有孩子都完成了工作,协程将进入已取消状态,并且isCompleted = true

父CoroutineContext解释 (Parent CoroutineContext explained)

In the task hierarchy, each coroutine has a parent that can be either a CoroutineScope or another coroutine. However, the resulting parent CoroutineContext of a coroutine can be different from the CoroutineContext of the parent since it’s calculated based on this formula:

在任务层次结构中,每个协程都有一个父级,该父级可以是CoroutineScope或另一个协程。 但是,协程的最终父CoroutineContext与父协程的CoroutineContext不同,因为它是根据以下公式计算的:

Parent context = Defaults + inherited CoroutineContext + arguments

父上下文 =默认值+继承的CoroutineContext +参数

Where:

哪里:

  • Some elements have default values: Dispatchers.Default is the default of CoroutineDispatcher and “coroutine” the default of CoroutineName.

    一些元素具有默认值: Dispatchers.DefaultCoroutineDispatcher 默认值, “coroutine”CoroutineName的默认值。

  • The inherited CoroutineContext is the CoroutineContext of the CoroutineScope or coroutine that created it.

    继承 CoroutineContextCoroutineContext中的CoroutineScope创建它或协程。

  • Arguments passed in the coroutine builder will take precedence over those elements in the inherited context.

    在协程生成器中传递的参数将优先于继承上下文中的那些元素。

Note: CoroutineContexts can be combined using the + operator. As the CoroutineContext is a set of elements, a new CoroutineContext will be created with the elements on the right side of the plus overriding those on the left. E.g. (Dispatchers.Main, “name”) + (Dispatchers.IO) = (Dispatchers.IO, “name”)

注意 :可以使用+运算符组合CoroutineContext 。 由于CoroutineContext是一组元素, CoroutineContext将创建一个新的CoroutineContext ,其中加号的右侧的元素会覆盖左侧的元素。 例如(Dispatchers.Main, “name”) + (Dispatchers.IO) = (Dispatchers.IO, “name”)

Image for post
Every coroutine started by this CoroutineScope will have at least those elements in the CoroutineContext. CoroutineName is gray because it comes from the default values.
由此CoroutineScope启动的每个协程至少在CoroutineContext中具有那些元素。 CoroutineName为灰色,因为它来自默认值。

Now that we know what’s the parent CoroutineContext of a new coroutine, its actual CoroutineContext will be:

现在我们知道新协程的父CoroutineContext是什么,其实际CoroutineContext将为:

New coroutine context = parent CoroutineContext + Job()

新的协程上下文 =父级CoroutineContext + Job()

If with the CoroutineScope shown in the image above we create a new coroutine like this:

如果使用上CoroutineScope所示的CoroutineScope ,我们将创建一个新的协程,如下所示:

val job = scope.launch(Dispatchers.IO) {
// new coroutine
}

What’s the parent CoroutineContext of that coroutine and its actual CoroutineContext? See the solution in the image below!

该协程及其实际CoroutineContext的父CoroutineContext是什么? 请参见下图中的解决方案!

Image for post
The Job in the CoroutineContext and in the parent context will never be the same instance as a new coroutine always get a new instance of a Job CoroutineContext和父上下文中的Job永远不会是同一实例,因为新的协程始终会获得Job的新实例

The resulting parent CoroutineContext has Dispatchers.IO instead of the scope’s CoroutineDispatcher since it was overridden by the argument of the coroutine builder. Also, check that the Job in the parent CoroutineContext is the instance of the scope’s Job (red color), and a new instance of Job (green color) has been assigned to the actual CoroutineContext of the new coroutine.

生成的父CoroutineContext具有Dispatchers.IO而不是作用域的CoroutineDispatcher因为它已被协CoroutineDispatcher器的参数覆盖。 此外,检查JobCoroutineContext是示波器的情况下Job (红色),和一个新的实例Job (绿色)被分配给实际CoroutineContext新协程。

As we will see in Part 3 of the series, a CoroutineScope can have a different implementation of Job called SupervisorJob in its CoroutineContext that changes how the CoroutineScope deals with exceptions. Therefore, a new coroutine created with that scope can have SupervisorJob as a parent Job. However, when the parent of a coroutine is another coroutine, the parent Job will always be of type Job.

正如我们将在本系列的第3部分中看到的那样, CoroutineScope可以在其CoroutineContext中具有一个称为SupervisorJobJob的不同实现,该CoroutineContext改变了CoroutineScope处理异常的方式。 因此,使用该范围创建的新协程可以将SupervisorJob作为父Job 。 但是,当协程的父级是另一个协程时,父级Job始终为Job类型。

Now that you know the basics of coroutines, start learning more about cancellation and exceptions in coroutines with Part II and Part III of this series:

既然您已经了解了协程的基础知识,请通过本系列的第二部分和第三部分开始学习更多有关协程中的取消和异常的信息:

翻译自: https://medium.com/androiddevelopers/coroutines-first-things-first-e6187bf3bb21

协程嵌套协程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值