当前位置: 首页 > news >正文

Kotlin 协程使用及其详解

Kotlin协程,好用,但是上限挺高的,我一直感觉自己就处于会用,知其然不知其所以然的地步。

做点小总结,比较浅显。后面自己再继续补充吧。

一、什么是协程?

Kotlin 协程是一种轻量级的并发编程方式,用于简化异步代码的编写。它允许你编写看似同步的代码来处理异步任务,使代码更加简洁、可读且易于维护。协程广泛应用于 Android 开发中,用于网络请求、数据库操作等需要异步执行的任务。

  • 协程是一种语法糖 协程的出现是来解决异步问题的,但它本身却不提供异步的能力,协程某种意义上更像是一种语法糖,它为我们隐藏了异步调用和回调的细节,让我们更关注于业务逻辑的实现。
  • 一句话概括,协程是一种轻量级的方便操作异步代码的语法糖,而它本身不提供异步能力。

二、Kotlin 协程的核心概念

  • 协程 (Coroutine):一种轻量级的线程。协程可以在不阻塞主线程的情况下挂起和恢复,使得代码能够异步执行而不增加线程开销。协程在 Kotlin 中由 suspend 函数来支持,避免回调地狱的情况。

  • 挂起函数 (suspend function):使用 suspend 关键字修饰的函数,可以在协程中挂起。挂起函数不会阻塞线程,而是挂起当前协程,直到任务完成后再继续执行。例如:

suspend fun fetchData(): String {// 模拟网络请求delay(1000)  // 挂起 1 秒,不会阻塞线程return "Data fetched"
}
  • 挂起 (Suspend) 和恢复 (Resume):当协程执行到 delaywithContext 等挂起函数时,它会暂停执行并释放资源,一旦挂起函数完成任务,协程会恢复执行。这种机制使得协程能够在同一线程上无缝切换,从而提高性能。

  • 作用域 (CoroutineScope):协程作用域定义了协程的生命周期。常见的协程作用域有 GlobalScopeCoroutineScopeviewModelScopelifecycleScope,它们决定了协程的启动与取消。作用域有助于自动管理协程,确保在不再需要协程时取消它,避免资源泄漏。

  • 上下文 (CoroutineContext):协程的上下文包含了协程的调度器(比如 Dispatchers.MainDispatchers.IO)和其他信息。上下文指定了协程在哪个线程或线程池上执行,调度器为协程提供执行环境。

三、协程的特点

  • 轻量

    • 一个线程中可以包含多个协程,协程支持挂起,不会让正在运行协程的线程阻塞,与阻塞线程相比,挂起协程的操作更轻量
  • 内存泄漏更少
    • 协程使用了结构化并发机制,可以在一个作用域内执行多个操作,可以一次性全部取消掉,这样就不用像 RxJava 一样要自己把 Disposable 放在 CompositeDisposable 里
  • 内置取消支持
    • 当我们取消一个协程时,取消操作会在运行中的整个协程层次结构内传播,也就是父协程取消后,子协程也会被取消
  • Jetpack支持
    • 集成 Jetpack 中的 ViewModel 、Lifecycle 和 LiveData 都提供了对应的协程作用域
  • Kotlin 协程框架中的挂起函数有另外一个好处,就是可以在编译时就让方法的调用方知道这是一个耗时的操作,需要确定这个操作要放在哪个线程执行,这样就不用像 Android 框架对主线程网络请求的禁止方式一样,在运行时才抛出异常。

四、协程和线程的区别

(1)协程是编译器级别的,线程是系统级别的。协程的切换是由程序来控制的,线程的切换是由操作系统来控制的。

(2)协程是协作式的,线程是抢占式的。协程是由程序来控制什么时候进行切换的,而线程是有操作系统来决定线程之间的切换的。

(3)一个线程可以包含多个协程。

(4)Java中,多线程可以充分利用多核cpu,协程是在一个线程中执行。

(5)协程适合io密集型的程序,多线程适合计算密集型的程序(适用于多核cpu的情况)。当你的程序大部分是文件读写操作或者网络请求操作的时候,这时你应该首选协程而不是多线程,首先这些操作大部分不是利用cpu进行计算而是等待数据的读写,其次因为协程执行效率较高,子程序切换不是线程切换,是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

(6)使用协程可以顺序调用异步代码,避免回调地狱。

五、协程的使用

Kotlin 提供了丰富的协程构建器,如 launchasync,分别用于启动协程并发任务。

1. launch

launch 是一种最常用的协程构建器,用于启动一个新协程,并且不会阻塞主线程。它的返回值是 Job,可以用于取消协程。

GlobalScope.launch {val result = fetchData()println(result)
}
2. async

async 用于并发执行多个任务,适合需要返回结果的情况。它的返回值是 Deferred,可以通过 await() 来获取执行结果。

CoroutineScope(Dispatchers.Main).launch {val result1 = async { fetchData() }val result2 = async { fetchData() }println(result1.await() + result2.await())
}

六、Job的使用

我们在使用launch的时候,就启动了一个协程,launch方法会返回一个job。

1.使用job.cancel()取消一个协程

fun main() {val job = GlobalScope.launch {delay(1000L)println("World!")}job.cancel()println("Hello,")}

因为协程被取消了,所以只会打印Hello。

2、join()等待协程执行完毕

作用类似于Thread.join()函数,join()后面的代码会等到协程结束再执行,结果如下:

fun main() = runBlocking {val job = GlobalScope.launch {delay(1000L)println("World!")delay(1000L)}println("Hello,")job.join() println("Good!")
}//依次打印
Hello,
World!
Good!

七、 其他注意事项

在Activity或Fragment中使用协程时,要尽量避免使用GlobalScope,因为GlobalScope是生命周期是process级别的,所以上面的例子中,即使Activity或Fragment已经被销毁,协程仍然在执行。

建议使用具有生命周期协程LifecycleScope。

关于kotlin相关的同步,异步,回调,阻塞,这篇文章很生动:

https://juejin.cn/post/7373502637729513506icon-default.png?t=O83Ahttps://juejin.cn/post/7373502637729513506retrofit搭配协程

https://juejin.cn/post/6962921891501703175icon-default.png?t=O83Ahttps://juejin.cn/post/6962921891501703175emmm...感觉写的很浅,还有很多知识点没有概括到,后面补充

相关文章:

Kotlin 协程使用及其详解

Kotlin协程,好用,但是上限挺高的,我一直感觉自己就处于会用,知其然不知其所以然的地步。 做点小总结,比较浅显。后面自己再继续补充吧。 一、什么是协程? Kotlin 协程是一种轻量级的并发编程方式&#x…...

计算机组成原理--三章四章

这里写目录标题 第三章:存储系统3.1 存储系统基本概念引入存储器的层次结构简介产品 存储器的分类按层次分类按照介质分类按照存取方式分类按照信息的可更改性按照信息的可保护性 存储器的性能指标存储容量单位成本存储速度 总结 3.2主存储器的基本组成半导体元器件…...

单片机工程使用链接优化-flto找不到定义_链接静态库

IDE: CLion HOST: Windows 11 MinGW:x86_64-14.2.0-release-posix-seh-ucrt-rt_v12-rev0 GCC: arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi 示例工程:https://github.com/ichliebedich-DaCapo/STM…...

UniTask/Unity的PlayerLoopTiming触发顺序

开始尝试在项目中使用UniTask,发现其中的UniTask.Yield确实很好用,还可以传入PlayerLoopTiming来更细致的调整代码时机,不过平常在Mono中接触的只有Awake,Start,Update等常用Timing,其他的就没怎么接触了&a…...

【报错记录】Steam迁移(移动)游戏报:移动以下应用的内容失败:XXX: 磁盘写入错误

前言 由于黑神话悟空,导致我的2TB的SSD系统盘快满了,我又买了一块4TB的SSD用来存放游戏,我就打算把之前C盘里的游戏移动到D盘,结果Steam移动游戏居然报错了,报的还是“磁盘写入错误”,如下图所示&#xff…...

C 语言学习-04【结构化程序设计】

1、单分支结构语句 用单分支结构进行奇偶判断&#xff1a; #include <stdio.h>int main() {int num;printf("Please enter an integer: ");scanf("%d", &num);if (num % 2 ! 0) {printf("%d is odd! \n", num);}if (num % 2 0) {prin…...

机器视觉:轮廓匹配算法原理

轮廓匹配的模板变量主要包括模板图像&#xff08;Template&#xff09;和待检测图像&#xff08;Source Image&#xff09; 在轮廓匹配中&#xff0c;模板变量主要包括一下几个关键部分&#xff1a; ‌模板图像&#xff08;Template&#xff09;‌&#xff1a;这是进行匹配的…...

动力商城-02 环境搭建

1.父工程必须满足&#xff1a;1.1删除src目录 1.2pom 2.依赖继承 //里面的依赖&#xff0c;后代无条件继承<dependencies></dependencies>//里面的依赖&#xff0c;后代想要继承&#xff0c;得自己声明需要使用&#xff0c;可以不写版本号&#xff0c;自动继承&l…...

【react】Redux基础用法

1. Redux基础用法 Redux 是一个用于 JavaScript 应用的状态管理库&#xff0c;它不依赖于任何 UI库&#xff0c;但常用于与 React 框架配合使用。它提供了一种集中式的状态管理方式&#xff0c;将应用的所有状态保存在一个单一的全局 Store&#xff08;存储&#xff09;中&…...

使用Python分析股票价格数据并计算移动平均线的实用指南

使用Python分析股票价格数据并计算移动平均线的实用指南 在金融市场中,移动平均线(Moving Average, MA)是一种常用的技术分析工具,用于平滑价格数据,帮助投资者识别趋势。本文将详细介绍如何使用Python分析股票价格数据,并计算移动平均线。我们将通过一个实际的案例来演…...

如何解决FPS低的问题?代码优化方法有哪些?

如果你是一名游戏开发者&#xff0c;或者对电脑性能有所追求的用户&#xff0c;那么你一定遇到过帧率&#xff08;FPS&#xff09;低的问题。帧率低会导致游戏卡顿、画面不流畅等问题&#xff0c;极大地影响了用户体验。本文将从代码层面探讨FPS低的原因&#xff0c;并提供一些…...

QT信号和槽与自定义的信号和槽

QT信号和槽与自定义的信号和槽 1.概述 这篇文章介绍下QT信号和槽的入门知识&#xff0c;通过一个案例介绍如何创建信号和槽&#xff0c;并调用他们。 2.信号和槽使用 下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。 创建按钮 在widget.cpp文件中创建按钮代码如下 …...

LC:二分查找——杂记

文章目录 268. 丢失的数字162. 寻找峰值 268. 丢失的数字 LC将此题归类为二分查找&#xff0c;并且为简单题&#xff0c;下面记一下自己对这道题目的思考。 题目链接&#xff1a;268.丢失的数字 第一次看到这个题目&#xff0c;虽然标注的为简单&#xff0c;但肯定不能直接排…...

GA/T1400视图库平台EasyCVR多品牌摄像机视频平台前端监控摄像头镜头的基础知识

在现代安全监控系统中&#xff0c;摄像机镜头作为捕捉图像的关键组件&#xff0c;其选择和应用直接影响到监控图像的质量和系统的整体性能。随着技术的发展&#xff0c;摄像机镜头的种类和功能也在不断扩展&#xff0c;以适应各种复杂的监控环境和需求。对于相机成像来讲&#…...

【C++】踏上C++的学习之旅(六):深入“类和对象“世界,掌握编程的黄金法则(一)

文章目录 前言1. "面向过程"和"面向对象"的碰撞1.1 面向过程1.2 面向对象 2. "类"的引入3. "类"的定义3.1 &#x1f349;语法展示&#xff1a;3.2 "类"的两种定义方式3.3 "类"的命名规则 4. 类的访问限定符以及封…...

【物联网技术】ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式

前言:讲解如何在ESP8266 WIFI模块在STA模式下作为TCP客户端与网络调试助手(TCP服务器)上电自动进入透传数据模式,而不需重新再发指令配置进入透传模式。 演示视频: ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式 wifi模块在STA模式下作为TCP客户端相…...

重构代码之用委托替代继承

在代码重构中&#xff0c;用委托替代继承 是一种用于改善代码设计和提高灵活性的重要技术。它的核心思想是&#xff0c;将子类与父类的直接继承关系转换为委托关系&#xff0c;即子类不再直接继承父类&#xff0c;而是通过持有父类的实例来访问所需的功能。 一、为什么需要用委…...

软件设计师下午题UML15分

一、涉及到的图及对应关系 二、例题 1.用例图和类图的例题 解析及答案 2.状态图和类图的例题 3.通信图和类图例题 例题...

css background-image背景图片轮播

1、CSS背景样式有以下几种&#xff1a; 背景颜色&#xff08;background-color&#xff09;&#xff1a;设置元素的背景颜色。背景图片&#xff08;background-image&#xff09;&#xff1a;设置元素的背景图片。背景重复&#xff08;background-repeat&#xff09;&#xff…...

java---认识异常(详解)

还有大家来到权权的博客~欢迎大家对我的博客提出意见哦&#xff0c;有错误会及时改进的~点击进入我的博客主页 目录 一、异常的概念及体系结构1.1 异常的概念1.2 异常的体系结构1.3异常的分类 二、异常的处理2.1防御式编程2.2 异常的抛出2.3 异常的捕获2.3.1异常声明throws2.3.…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

免费PDF转图片工具

免费PDF转图片工具 一款简单易用的PDF转图片工具&#xff0c;可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件&#xff0c;也不需要在线上传文件&#xff0c;保护您的隐私。 工具截图 主要特点 &#x1f680; 快速转换&#xff1a;本地转换&#xff0c;无需等待上…...

SpringAI实战:ChatModel智能对话全解

一、引言&#xff1a;Spring AI 与 Chat Model 的核心价值 &#x1f680; 在 Java 生态中集成大模型能力&#xff0c;Spring AI 提供了高效的解决方案 &#x1f916;。其中 Chat Model 作为核心交互组件&#xff0c;通过标准化接口简化了与大语言模型&#xff08;LLM&#xff0…...

Spring Boot + MyBatis 集成支付宝支付流程

Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例&#xff08;电脑网站支付&#xff09; 1. 添加依赖 <!…...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...

Vue 3 + WebSocket 实战:公司通知实时推送功能详解

&#x1f4e2; Vue 3 WebSocket 实战&#xff1a;公司通知实时推送功能详解 &#x1f4cc; 收藏 点赞 关注&#xff0c;项目中要用到推送功能时就不怕找不到了&#xff01; 实时通知是企业系统中常见的功能&#xff0c;比如&#xff1a;管理员发布通知后&#xff0c;所有用户…...

从零手写Java版本的LSM Tree (一):LSM Tree 概述

&#x1f525; 推荐一个高质量的Java LSM Tree开源项目&#xff01; https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree&#xff0c;专为高并发写入场景设计。 核心亮点&#xff1a; ⚡ 极致性能&#xff1a;写入速度超…...

Python第七周作业

Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt&#xff0c;并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径&#xff0c;并创建logs目录&#xff08;若不存在&#xff09; 3.递归遍历目录data&#xff0c;输出所有.csv文件的路径…...