深入理解Kotlin协程suspend工作原理(初学者也能看得懂)

简介: 深入理解Kotlin协程suspend工作原理(初学者也能看得懂)

1. 概述



挂起函数是Kotlin协程最重要的一个特性,所有其他概念都建立在它的基础上。所以我们需要深入了解它的工作原理。


挂起协程意味着在中间停止它。这类似于玩游戏,当我们想暂停游戏时,可以先存档,想继续游戏时,可以从存档处恢复游戏。当协程被暂停时,它会返回一个Continuation. 这就像游戏中的存档,协程可以使用Continuation从挂起的地方恢复。


请注意,这与线程非常不同,线程无法保存,只能阻塞。协程要强大得多,挂起时,它不消耗任何所在线程的资源。协程不一定需要在启动协程的线程上恢复,可以切换到不同的线程上。


2. 恢复



让我们看看它的实际效果。我们使用协程构建器(如runBlocking或launch)启动协程。suspend函数是可以挂起协程的函数。这意味着,它们必须在协程(或另一个挂起函数)上调用。


image.png


这是一个简单的程序,将打印“Before”和“After”。如果我们在中间调用协程标准库提供的suspendCoroutine函数会怎样呢?

image.png

如果你执行上面的代码,你将发现不会打印“After”,并且main函数不会退出。协程在“Before”之后暂停。我们的程序停止了,再也没有恢复。那我们怎么做呢?我们可以使用Continuation来恢复程序?


我们观察下suspendCoroutine调用,注意它以 lambda 表达式 ( { })结尾。作为参数传递的函数将在暂停之前被调用。此函数将Continuation作为参数。


image.png

观察打印日志,我们发现“After”仍然没有打印。我们可以用Continuation的resume方法让协程恢复执行。

image.png

请注意,上面示例中的“After”被打印出来,因为我们在suspendCoroutine中调用resume函数。


从 Kotlin 1.3 开始, Continuation的定义发生了变化。resumeWith函数代替了resume和resumeWithException函数。我们使用的resume和resumeWithException是标准库中的扩展函数。


image.png

我们还可以使用它来启动一个不同的线程,该线程将休眠一段时间后恢复:


image.png


我们还可以将启动线程的代码提取到一个函数中。

image.png

这种机制是有效的,但是我们也可以用线程池来代替线程。

image.png

暂停一段时间似乎是一个有用的功能。让我们把它提取成一个函数。我们将命名它delay。


image.png


这正是Kotlin协程库delay方法曾经的实现方式。目前的实现比较复杂,主要是为了支持测试,但是本质思路还是一样的。


3. 带值恢复



您可能需要注意的是我们为什么将Unit传递给resume函数,为什么我们将Unit作为suspendCoroutine函数泛型类型。Unit是suspendCoroutine函数的返回类型,也是Continuation的泛型类型。


image.png

image.png


当我们调用suspendCoroutine时,我们可以指定Continuation中的返回类型。resume函数需要调用与之相同的类型。


image.png


挂起对协程非常有意义。当我们做耗时操作时,我们需要被挂起。例如,当我们需要从API获取网络响应时,如果没有协程,这个线程就需要等待。因为线程很昂贵,这将是一个巨大的浪费。特别是当这是一个重要的线程,比如 Android 上的主线程。使用协程,它只是挂起协程,然后线程可以去做其他事情。一旦数据到了,线程将从协程挂起点恢复。


举个例子,我们模拟网络请求用户信息:


image.png

直接在main方法中调用suspendCoroutine不太方便。我们可以把它提取成一个方法。


image.png


目前,许多流行的库如Retrofit或Room已经支持suspend函数。这就是为什么我们很少需要在suspend函数中使用回调函数的原因。还有一个和suspendCoroutine类似的方法suspendCancellableCoroutine,我推荐你使用后者,后者支持取消功能。


你可能想知道如果API不给我们数据而是返回异常会怎样。如果服务死机或响应错误会怎样?。在这种情况下,我们不能返回数据,而是应该从协程挂起的地方抛出异常


4. 异常恢复



我们调用的每个函数都可能返回某个值或抛出异常。对于suspendCoroutine也是如此。我们可以调用resumeWithException从异常处返回。可以用try catch捕获异常。


image.png

image.png

5. 挂起一个协程,而不是一个函数



需要强调的一件事是我们只是暂停了一个协程,而不是一个函数。想象一下,我们将Continuation存储在某个变量中,并尝试在函数调用后恢复它。


image.png

这没有任何意义。resume永远不会被调用。


image.png

相关文章
|
2月前
|
Java 数据库 Android开发
【专栏】Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理
【4月更文挑战第27天】本文探讨了Kotlin在Android开发中的多线程优化,包括线程池、协程的使用,任务分解、避免阻塞操作以及资源管理。通过案例分析展示了网络请求、图像处理和数据库操作的优化实践。同时,文章指出并发编程的挑战,如性能评估、调试及兼容性问题,并强调了多线程优化对提升应用性能的重要性。开发者应持续学习和探索新的优化策略,以适应移动应用市场的竞争需求。
|
2月前
|
传感器 Android开发 开发者
构建高效Android应用:Kotlin的协程与Flow
【4月更文挑战第26天】随着移动应用开发的不断进步,开发者寻求更简洁高效的编码方式以应对复杂多变的业务需求。在众多技术方案中,Kotlin语言凭借其简洁性和强大的功能库逐渐成为Android开发的主流选择。特别是Kotlin的协程和Flow这两个特性,它们为处理异步任务和数据流提供了强大而灵活的工具。本文将深入探讨如何通过Kotlin协程和Flow来优化Android应用性能,实现更加流畅的用户体验,并展示在实际开发中的应用实例。
|
2月前
|
移动开发 Java Android开发
构建高效Android应用:Kotlin与协程的完美融合
【2月更文挑战第25天】 在移动开发领域,性能优化和应用响应性的提升是永恒的追求。随着Android Jetpack组件库的不断丰富,Kotlin语言已经成为Android开发的首选。而Kotlin协程作为一种新的并发处理方案,它以轻量级线程的形式,为开发者提供了简洁高效的异步编程手段。本文将深入探讨Kotlin协程在Android应用中的实践运用,以及如何通过这种技术改善用户界面的流畅度和后台任务的处理能力,进而构建出更高效、更稳定的Android应用。
|
2月前
|
安全 Android开发 开发者
构建高效Android应用:Kotlin与协程的完美结合
【2月更文挑战第30天】在移动开发领域,性能优化和流畅的用户体验是关键。本文深入探讨了如何通过结合Kotlin语言和协程技术来提升Android应用的性能和响应能力。我们将分析Kotlin的优势,介绍协程的基本概念,并通过实际案例展示如何在应用中实现协程以简化异步编程,从而提供更加高效的解决方案。
|
2月前
|
API 调度
2.3.1 协程设计原理与汇编实现
2.3.1 协程设计原理与汇编实现
|
18天前
|
存储 Java 调度
Android面试题之Kotlin 协程的挂起、执行和恢复过程
了解Kotlin协程的挂起、执行和恢复机制。挂起时,状态和上下文(局部变量、调用栈、调度器等)被保存;挂起点通过`Continuation`对象处理,释放线程控制权。当恢复条件满足,调度器重新分配线程,调用`resumeWith`恢复执行。关注公众号“AntDream”获取更多并发知识。
28 2
|
2月前
|
移动开发 Android开发 开发者
构建高效Android应用:Kotlin与协程的完美融合
【5月更文挑战第25天】 在移动开发的世界中,性能和响应性是衡量应用质量的关键指标。随着Kotlin的流行和协程的引入,Android开发者现在有了更强大的工具来提升应用的性能和用户体验。本文深入探讨了Kotlin语言如何与协程相结合,为Android应用开发带来异步处理能力的同时,保持代码的简洁性和可读性。我们将通过实际案例分析,展示如何在Android项目中实现协程,以及它们如何帮助开发者更有效地管理后台任务和用户界面的流畅交互。
|
2月前
|
移动开发 数据库 Android开发
构建高效Android应用:探究Kotlin的协程优势
【5月更文挑战第22天】随着移动开发技术的不断进步,Android平台的性能优化已经成为开发者关注的焦点。在众多提升应用性能的手段中,Kotlin语言提供的协程概念因其轻量级线程管理和异步编程能力而受到广泛关注。本文将深入探讨Kotlin协程在Android开发中的应用,以及它如何帮助开发者构建出更高效、响应更快的应用,同时保持代码的简洁性和可读性。
|
2月前
|
移动开发 监控 Android开发
构建高效安卓应用:Kotlin 协程的实践与优化
【5月更文挑战第16天】 在移动开发领域,性能优化一直是开发者们追求的重要目标。特别是对于安卓平台来说,由于设备多样性和系统资源的限制,如何提升应用的响应性和流畅度成为了一个关键议题。近年来,Kotlin 语言因其简洁、安全和高效的特点,在安卓开发中得到了广泛的应用。其中,Kotlin 协程作为一种轻量级的并发解决方案,为异步编程提供了强大支持,成为提升安卓应用性能的有效手段。本文将深入探讨 Kotlin 协程在安卓开发中的应用实践,以及通过合理设计和使用协程来优化应用性能的策略。
33 8
|
2月前
|
移动开发 Android开发 开发者
构建高效安卓应用:Kotlin 协程的实践指南
【5月更文挑战第18天】 随着移动开发技术的不断进步,安卓平台亟需一种高效的异步编程解决方案来应对日益复杂的应用需求。Kotlin 协程作为一种新兴的轻量级线程管理机制,以其简洁的语法和强大的功能,成为解决这一问题的关键。本文将深入探讨Kotlin协程在安卓开发中的实际应用,从基本概念到高级技巧,为开发者提供一份全面的实践指南,旨在帮助读者构建更加高效、稳定的安卓应用。