Kotlin 协程使用及其详解
Kotlin协程,好用,但是上限挺高的,我一直感觉自己就处于会用,知其然不知其所以然的地步。
做点小总结,比较浅显。后面自己再继续补充吧。
一、什么是协程?
Kotlin 协程是一种轻量级的并发编程方式,用于简化异步代码的编写。它允许你编写看似同步的代码来处理异步任务,使代码更加简洁、可读且易于维护。协程广泛应用于 Android 开发中,用于网络请求、数据库操作等需要异步执行的任务。
- 协程是一种语法糖 协程的出现是来解决异步问题的,但它本身却不提供异步的能力,协程某种意义上更像是一种语法糖,它为我们隐藏了异步调用和回调的细节,让我们更关注于业务逻辑的实现。
- 一句话概括,协程是一种轻量级的方便操作异步代码的语法糖,而它本身不提供异步能力。
二、Kotlin 协程的核心概念
-
协程 (Coroutine):一种轻量级的线程。协程可以在不阻塞主线程的情况下挂起和恢复,使得代码能够异步执行而不增加线程开销。协程在 Kotlin 中由
suspend函数来支持,避免回调地狱的情况。 -
挂起函数 (
suspendfunction):使用suspend关键字修饰的函数,可以在协程中挂起。挂起函数不会阻塞线程,而是挂起当前协程,直到任务完成后再继续执行。例如:
suspend fun fetchData(): String {// 模拟网络请求delay(1000) // 挂起 1 秒,不会阻塞线程return "Data fetched"
}
-
挂起 (Suspend) 和恢复 (Resume):当协程执行到
delay、withContext等挂起函数时,它会暂停执行并释放资源,一旦挂起函数完成任务,协程会恢复执行。这种机制使得协程能够在同一线程上无缝切换,从而提高性能。 -
作用域 (
CoroutineScope):协程作用域定义了协程的生命周期。常见的协程作用域有GlobalScope、CoroutineScope、viewModelScope和lifecycleScope,它们决定了协程的启动与取消。作用域有助于自动管理协程,确保在不再需要协程时取消它,避免资源泄漏。 -
上下文 (
CoroutineContext):协程的上下文包含了协程的调度器(比如Dispatchers.Main、Dispatchers.IO)和其他信息。上下文指定了协程在哪个线程或线程池上执行,调度器为协程提供执行环境。
三、协程的特点
轻量
- 一个线程中可以包含多个协程,协程支持挂起,不会让正在运行协程的线程阻塞,与阻塞线程相比,挂起协程的操作更轻量
- 内存泄漏更少
- 协程使用了结构化并发机制,可以在一个作用域内执行多个操作,可以一次性全部取消掉,这样就不用像 RxJava 一样要自己把 Disposable 放在 CompositeDisposable 里
- 内置取消支持
- 当我们取消一个协程时,取消操作会在运行中的整个协程层次结构内传播,也就是父协程取消后,子协程也会被取消
- Jetpack支持
- 集成 Jetpack 中的 ViewModel 、Lifecycle 和 LiveData 都提供了对应的协程作用域
- Kotlin 协程框架中的挂起函数有另外一个好处,就是可以在编译时就让方法的调用方知道这是一个耗时的操作,需要确定这个操作要放在哪个线程执行,这样就不用像 Android 框架对主线程网络请求的禁止方式一样,在运行时才抛出异常。
四、协程和线程的区别
(1)协程是编译器级别的,线程是系统级别的。协程的切换是由程序来控制的,线程的切换是由操作系统来控制的。
(2)协程是协作式的,线程是抢占式的。协程是由程序来控制什么时候进行切换的,而线程是有操作系统来决定线程之间的切换的。
(3)一个线程可以包含多个协程。
(4)Java中,多线程可以充分利用多核cpu,协程是在一个线程中执行。
(5)协程适合io密集型的程序,多线程适合计算密集型的程序(适用于多核cpu的情况)。当你的程序大部分是文件读写操作或者网络请求操作的时候,这时你应该首选协程而不是多线程,首先这些操作大部分不是利用cpu进行计算而是等待数据的读写,其次因为协程执行效率较高,子程序切换不是线程切换,是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
(6)使用协程可以顺序调用异步代码,避免回调地狱。
五、协程的使用
Kotlin 提供了丰富的协程构建器,如 launch 和 async,分别用于启动协程并发任务。
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/7373502637729513506
https://juejin.cn/post/7373502637729513506retrofit搭配协程
https://juejin.cn/post/6962921891501703175
https://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移动游戏居然报错了,报的还是“磁盘写入错误”,如下图所示ÿ…...
C 语言学习-04【结构化程序设计】
1、单分支结构语句 用单分支结构进行奇偶判断: #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…...
机器视觉:轮廓匹配算法原理
轮廓匹配的模板变量主要包括模板图像(Template)和待检测图像(Source Image) 在轮廓匹配中,模板变量主要包括一下几个关键部分: 模板图像(Template):这是进行匹配的…...
动力商城-02 环境搭建
1.父工程必须满足:1.1删除src目录 1.2pom 2.依赖继承 //里面的依赖,后代无条件继承<dependencies></dependencies>//里面的依赖,后代想要继承,得自己声明需要使用,可以不写版本号,自动继承&l…...
【react】Redux基础用法
1. Redux基础用法 Redux 是一个用于 JavaScript 应用的状态管理库,它不依赖于任何 UI库,但常用于与 React 框架配合使用。它提供了一种集中式的状态管理方式,将应用的所有状态保存在一个单一的全局 Store(存储)中&…...
使用Python分析股票价格数据并计算移动平均线的实用指南
使用Python分析股票价格数据并计算移动平均线的实用指南 在金融市场中,移动平均线(Moving Average, MA)是一种常用的技术分析工具,用于平滑价格数据,帮助投资者识别趋势。本文将详细介绍如何使用Python分析股票价格数据,并计算移动平均线。我们将通过一个实际的案例来演…...
如何解决FPS低的问题?代码优化方法有哪些?
如果你是一名游戏开发者,或者对电脑性能有所追求的用户,那么你一定遇到过帧率(FPS)低的问题。帧率低会导致游戏卡顿、画面不流畅等问题,极大地影响了用户体验。本文将从代码层面探讨FPS低的原因,并提供一些…...
QT信号和槽与自定义的信号和槽
QT信号和槽与自定义的信号和槽 1.概述 这篇文章介绍下QT信号和槽的入门知识,通过一个案例介绍如何创建信号和槽,并调用他们。 2.信号和槽使用 下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。 创建按钮 在widget.cpp文件中创建按钮代码如下 …...
LC:二分查找——杂记
文章目录 268. 丢失的数字162. 寻找峰值 268. 丢失的数字 LC将此题归类为二分查找,并且为简单题,下面记一下自己对这道题目的思考。 题目链接:268.丢失的数字 第一次看到这个题目,虽然标注的为简单,但肯定不能直接排…...
GA/T1400视图库平台EasyCVR多品牌摄像机视频平台前端监控摄像头镜头的基础知识
在现代安全监控系统中,摄像机镜头作为捕捉图像的关键组件,其选择和应用直接影响到监控图像的质量和系统的整体性能。随着技术的发展,摄像机镜头的种类和功能也在不断扩展,以适应各种复杂的监控环境和需求。对于相机成像来讲&#…...
【C++】踏上C++的学习之旅(六):深入“类和对象“世界,掌握编程的黄金法则(一)
文章目录 前言1. "面向过程"和"面向对象"的碰撞1.1 面向过程1.2 面向对象 2. "类"的引入3. "类"的定义3.1 🍉语法展示:3.2 "类"的两种定义方式3.3 "类"的命名规则 4. 类的访问限定符以及封…...
【物联网技术】ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式
前言:讲解如何在ESP8266 WIFI模块在STA模式下作为TCP客户端与网络调试助手(TCP服务器)上电自动进入透传数据模式,而不需重新再发指令配置进入透传模式。 演示视频: ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式 wifi模块在STA模式下作为TCP客户端相…...
重构代码之用委托替代继承
在代码重构中,用委托替代继承 是一种用于改善代码设计和提高灵活性的重要技术。它的核心思想是,将子类与父类的直接继承关系转换为委托关系,即子类不再直接继承父类,而是通过持有父类的实例来访问所需的功能。 一、为什么需要用委…...
软件设计师下午题UML15分
一、涉及到的图及对应关系 二、例题 1.用例图和类图的例题 解析及答案 2.状态图和类图的例题 3.通信图和类图例题 例题...
css background-image背景图片轮播
1、CSS背景样式有以下几种: 背景颜色(background-color):设置元素的背景颜色。背景图片(background-image):设置元素的背景图片。背景重复(background-repeat)ÿ…...
java---认识异常(详解)
还有大家来到权权的博客~欢迎大家对我的博客提出意见哦,有错误会及时改进的~点击进入我的博客主页 目录 一、异常的概念及体系结构1.1 异常的概念1.2 异常的体系结构1.3异常的分类 二、异常的处理2.1防御式编程2.2 异常的抛出2.3 异常的捕获2.3.1异常声明throws2.3.…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
