android kotlin 协程(一) 简单入门

news2025/6/9 13:33:16

android kotlin 协程(一)

config:

  • system: macOS

  • android studio: 2022.1.1 Electric Eel

  • gradle: gradle-7.5-bin.zip

  • android build gradle: 7.1.0

  • Kotlin coroutine core: 1.6.4

前言:最近系统的学习了一遍协程, 计划通过10篇左右blog来记录一下我对协程的理解, 从最简单的 runBlocking开始; 到最后 suspend和continuation的关系等等

tips:前面几篇全都是协程的基本使用,没有源码,等后面对协程有个基本理解之后,才会简单的分析一下源码!

学习我这个系列的协程, 只需要记住一点, suspend函数 永远不会阻塞main线程执行! 永远是异步的!

看完本篇你将会学到哪些知识:

  • runBlocking()
  • CoroutineScope#launch()
  • CoroutineScope#async()
  • Job的常用方法
  • 协程状态[isActive,isCancelled,isCompleted]

runBlocking

定义: runBlocking 会阻塞线程来等待自己子协程执行完, 并且对于不是子协程的作用域,也会尽量的去执行,

首先来了解一下什么是自己的子协程

image-20230209134504138

通常我们通过

  • CoroutineScope.launch{}
  • CoroutineScope.async{}

来开启一个协程,因为当前是在CoroutineScope作用域中,所以直接launch / async 即可

这段代码可以看出,runBlocking 会等待子协程全部执行完,然后在结束任务,因为协程都是异步的,

所以会先执行协程之外的代码,然后再执行协程中的代码

可以在协程中添加一些睡眠操作再来测试一下

image-20230209135225296

可以看出,还是可以正常的执行完所有代码

现在解释完了定义中的前半句话: runBlocking 会阻塞线程来等待自己子协程执行完, 并且对于不是子协程的作用域,也会尽量的去执行,

再来看一下后半句话:

image-20230209135639421

可以看出,通过自定义coroutine 和 GlobalScope,来创建的协程照样可以执行出来

那么在他们之中稍微添加一点逻辑会怎么样?

image-20230209140524725

可以看出,一旦添加了一点逻辑, runBlocking是不会等待非子协程的作用域

如果想让runBlocking等待非子协程执行完,那么只需要调用Job.#join() 即可

例如这样:

image-20230209141429449

join()方法目前可以理解为: 等待当前协程执行完 在往下执行其他代码,

一旦调用了join()方法,那么协程就变成了同步的,那么这块代码一共执行需要4s

因为协程1并没有join, 所以协程1还是异步的,

协程2调用了join,所以在执行协程2的过程中,协程1也在执行.

所以协程1,与协程2的执行时间为2s

image-20230209142033645

tips: 在开发中不建议使用runBlocking,因为会阻塞主线程,阻塞主线程的时间,用来子协程的执行…

开启协程两种不同的方式

在上面代码中我们提到了,开启协程有2种方式

  • CoroutineScope#launch{}
  • CoroutineScope#async{}

先来看相同点:

image-20230209143252217

相同点就是无论是哪种方式,都会执行里面的代码

那么这两种方式有什么区别呢?

  • launch无法返回数据, async可以返回结果

    image-20230209143141023

返回的结果通过 Deferred#await() 来获取,并且调用Deferred#await()的时候,会等待async{} 执行完成之后在往下执行,就和Job#join一样,不过await()有返回结果

使用await的时候有一个注意点:

image-20230209143832540

那么也可以看到,launch{} 与 async{} 的返回值也有所不同:

  • launch{} 返回 Job
  • async{} 返回Deferred

其实本质上来说,async 返回的也是Job,不过只是Job的子类Deferred而已,Deferred只是对返回值等一些操作的封装

image-20230209144036904

那么Job是用来干什么的呢?

Job是用来管理协程的生命周期的, 例如刚才提到的 Job.join() 就可以让协程 “立即执行”

launch{} 和 async{} 捕获异常的方式也不同,这个等下一篇专门聊异常的时候在详细讲解

Job.cancel 取消协程

协程比线程好用的一点就是协程可以自己管理生命周期, 而线程则不可以

image-20230209145025542

这里需要注意的是,如果协程体中还在执行,但是外部已经取消了,那么则会throw异常出来

JobCancellationException

fun main() = runBlocking<Unit> {
    println("main start")

    val job = launch {
        try {
            (0..100).forEachIndexed { index, _ ->
                delay(1000)
                println("launch $index")
            }
        } catch (e: Exception) {
            println("协程被取消了 $e")
        }
    }

    // 协程执行完成监听
    job.invokeOnCompletion {
        println("协程执行完毕${it}")
    }

    delay(5500)

    // 取消协程
    job.cancel()

    println("main end")
}

Job#invokeOnCompletion: 协程完成回调

运行结果:

main start
launch 0
launch 1
launch 2
launch 3
launch 4
main end
协程被取消了 kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job="coroutine#2":StandaloneCoroutine{Cancelling}@76a4d6c
协程执行完毕kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job="coroutine#2":StandaloneCoroutine{Cancelled}@76a4d6c

coroutine的3种状态

coroutine的三种状态都是通过Job来管理的:

  • isActive 是否是活跃状态
  • isCancelled 是否取消
  • isCompleted 是否完成

先来看看正常流程执行的代码:

image-20230209151017683

我们知道协程始终是异步执行的,在执行printlnJob的时候,协程体中的代码还没有真正的执行

所以此时处于活跃状态,并且协程没有被执行完

如果我们在协程执行完成的回调中调用

image-20230209151208403

那么此时,协程体中的代码已经执行完了,那么此时就是非活跃状态

还剩一个Job#isCancelled 这个方法比较简单,简单的说就是是否调用了Job.cancel()

image-20230209151653026

但是这里有一个特别奇怪的点,明明已经调用Job#cancel() 来取消协程,并且协程体中的代码也没执行,但是为什么还显示协程没有执行完呢?

因为Job#cancel() 并不是suspend函数,不是suspend函数就没有恢复功能,这行文字可能看的有一点迷惑,先不用管什么挂起于恢复,现在只需要知道

我们调用cancel() 的时候会紧跟着一个,Job#join() 即可

或者直接调用Job.cancelAndJoin() 即可

image-20230209152145627

挂起恢复,这4个字我理解了10天左右,不可能通过本篇就讲清楚,现在只需要会调用这些api,即可!!

那么问题就来了,这个状态有什么用呢?

先来看一段代码:

Feb-09-2023 15-40-30

可以惊奇的发现,这段代码无论如何都cancel不掉.好像是失效了一样

那么解决这个问题,就可以检测协程是否是活跃状态,例如这样

Feb-09-2023 15-43-37

Job也提供了一个方法: Job#ensureActive()

ensureActive() 本质也是通过isActive判断,不同的是,当取消的时候可以捕获到取消的异常,然后来处理对应的事件

图片地址

回顾一下本篇:

本篇我们讲解了runBlocking, 这个函数会帮我们阻塞主线程, 阻塞住线程的时候会等待内部的子协程全部执行完

还聊了最基础的如何开启一个协程, launch / async 以及他们的相同点和不同点

最后引出了协程生命周期管理者Job, 讲解了Job常用的方法,以及job的3种状态

方法名作用补充
join()立即恢复协程体执行等待协程体执行完成,在执行后续代码
cancel()取消协程,如果取消时,协程体还在执行,这throw JobCancellationException,这个异常不会上报,会自行处理
invokeOnCompletion()协程体执行完成回调
isActive协程体是否是活跃状态
isCancelled协程体是否被取消
isCompleted协程体是否执行完成

完整代码

下一篇预告:

  • CoroutineDispatcher // 协程调度器 用来切换线程

  • CoroutineName // 协程名字

  • CoroutineStart // 协程启动模式

  • CoroutineException // launch / async 捕获异常

  • GlobalCoroutineException // 全局捕获异常

原创不易,您的点赞就是我最大的支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/334290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

视频融合平台EasyCVR集成宇视SDK关闭“按需直播”,一直未拉流是什么原因?

EasyCVR平台不仅能提供丰富的视频能力&#xff0c;还可提供云、边、端分布式海量视频资源的统一管理与运维&#xff0c;从而实现数据采集、处理、汇聚、分析、存储、管理等全环节的视频能力。借助智能分析网关的AI智能检测能力&#xff0c;可实现人脸、人体、车辆、烟火、物体、…

(十五)双边滤波Bilateral Filter

文章目录mathjax: true1.高斯滤波1.1 理论1.2 示例2.双边滤波&#xff08;Bilateral Filter&#xff09;2.1 理论基础2.2 OpenCV bilateralFilter函数参考资料欢迎访问个人网络日志&#x1f339;&#x1f339;知行空间&#x1f339;&#x1f339; title: 3.双边滤波BilateralFi…

微信小程序 java基于Android老年人智慧服务平台-

目录 1绪论 4 1.1项目研究的背景 4 1.2开发意义 4 1.3项目研究内容 4 1.4论文结构 4 2开发技术介绍 6 2.1B/S架构 6 2.2 Android平台 6 2.3 Java语言简介 6 2.4 MySQL 介绍 7 2.5 MySQL环境配置 8 2.6 SSM框架 8 3系统分析 9 3.1可行性分析 9 3.1.1技术可行性 9 3.1.2经济可行性…

【图像异常检测】 Anomalib

原文&#xff1a; A practical guide to image-based anomaly detection using Anomalib 1. 简介 在工业生产中&#xff0c;质量保证是一个很重要的话题&#xff0c; 因此在生产中细小的缺陷需要被可靠的检出。工业异常检出旨在从正常的样本中检测异常的、有缺陷的情况。工业…

构建工具tsup入门第四部分

&#x1f384;Hi~ 大家好&#xff0c;我是小鑫同学&#xff0c;一位长期从事前端开发的编程爱好者&#xff0c;我将使用更为实用的案例输出更多的编程知识&#xff0c;同时我信奉分享是成长的唯一捷径&#xff0c;在这里也希望我的每一篇文章都能成为你技术落地的参考~ 目录&am…

哈夫曼树、带权路径长度、前缀编码 的概念

文章目录一、基本概念1.1带权路径长度&#xff08;WPL&#xff09;1.2哈夫曼树二、哈夫曼树的构造三、哈夫曼树的应用3.1哈夫曼编码与前缀编码一、基本概念 1.1带权路径长度&#xff08;WPL&#xff09; 路径长度&#xff1a; 经历的边数 结点的带权路径长度&#xff1a; 从树…

创建线程的三种模式

进程&#xff0c;是对运行时程序的封装&#xff0c;是系统进行资源调度和分配的基本单位&#xff0c;实现了操作系统的并发。 线程&#xff0c;是进程的子任务&#xff0c;是CPU调度和分派的基本单位&#xff0c;实现了进程内部的并发。 线程在进程下运行。 进程之间不会影响…

从0到1一步一步玩转openEuler--09 openEuler基础配置--设置日期和时间

文章目录9 设置日期和时间9.1 使用timedatectl命令设置9.1.1 显示日期和时间9.1.2 通过远程服务器进行时间同步9.1.3 修改日期9.1.4 修改时间9.1.5 修改时区9.2 使用date命令设置9.2.1 显示当前的日期和时间9.2.2 修改时间9.2.3 修改日期9.3 使用hwclock命令设置9.3.1 硬件时钟…

QT之OpenGL深度测试

QT之OpenGL深度测试1. 深度测试概述1. 1 提前深度测试1.2 深度测试相关函数2. 深度测试精度2.1 深度冲突3. Demo4. 参考1. 深度测试概述 在OpenGL中深度测试(Depth Testing)是关闭的&#xff0c;此时在渲染图形时会产生一种现象后渲染的会把最先渲染的遮挡住。而在启用深度测试…

浏览器的底层运行机制

一、复习 1.进程和线程 进程&#xff1a;指一个程序(或浏览器打开一个页面就是开辟一个进程)* 线程&#xff1a;程序中具体执行任务的一个进程中可能包含一到多个线程&#xff01;&#xff01;* 单线程&#xff1a;同时只能处理一件事&#xff0c;上一件事处理完&#xff0c;…

ASEMI三相整流模块MDS55-16特征,MDS55-16应用

编辑-Z ASEMI三相整流模块MDS55-16参数&#xff1a; 型号&#xff1a;MDS55-16 最大重复峰值反向电压&#xff08;VRRM&#xff09;&#xff1a;1600V 最大RMS电桥输入电压&#xff08;VRMS&#xff09;&#xff1a;1700V 最大平均正向整流输出电流&#xff08;IF&#xf…

MySQL架构图

MySQL架构图 Mysql逻辑架构图主要分三层&#xff1a; 1) 第一层负责连接处理&#xff0c;授权认证&#xff0c;安全等等 每个客户端连接都会在服务器进程中拥有一个线程&#xff0c;服务器维护了一个线程池&#xff0c;因此不需要为每一个新建的连接创建或者销毁线程。 当客户…

看板管理对项目管理有什么帮助?

在目前市面上的项目管理工具中&#xff0c;项目看板功能基本上成为了标配。看板作为敏捷的项目管理工具&#xff0c;可以帮助我们将项目工作可视化展现。项目看板的作用1&#xff0c;提高团队信息流动性&#xff1a;看板工具可以及时的传递项目工作中的最新讯息&#xff0c;保证…

Mapper文件注入问题

Mapper文件注入问题UserMapper that could not be found.原因分析解决方案程序正常运行&#xff0c;但是注入类爆红问题原因分析解决方法UserMapper’ that could not be found. 原因分析 撰写了mapper文件&#xff0c;但是没有注入spring容器 解决方案 添加mybatis.mapper-…

DVWA—CSRF-Medium跨站请求伪造中级

注意&#xff1a; 1、这里对XSS(Stored)关卡不熟悉的可以从这里去看http://t.csdn.cn/ggQDK 2、把难度设置成 Medium 一、这一关同样我们需要埋下伏笔&#xff0c;诱使用户点击来提交&#xff0c;首先从XSS&#xff08;Stored&#xff09;入手。 注意&#xff1a;在前面介绍…

黑马】后台项目171集

将近一个月没有练习了&#xff0c;找到之后果然打不开出了问题【问题】运行代码打开网页后&#xff0c;发现不能正常登录&#xff0c;一开始还以为是密码记错了&#xff0c;后来发现是数据库没有正常启动&#xff0c;phpstudy中的数据库一直是启动状态&#xff0c;关闭不了。【…

这个神器,让 Python 爬虫如此简单

相信大家应该都写过爬虫&#xff0c;简单的爬虫只需要使用 requests 即可。遇到复杂的爬虫&#xff0c;就需要在程序里面加上请求头和参数信息。类似这种&#xff1a; 我们一般的步骤是&#xff0c;先到浏览器的网络请求中找到我们需要的请求&#xff0c;然后将请求头和参数信…

【运筹优化】带时间窗约束的车辆路径规划问题(VRPTW)详解 + Python 调用 Gurobi 建模求解

文章目录一、概述1.1 VRP 问题1.2 CVRP 问题1.3 VRPTW 问题二、VRPTW 的一般模型三、Python 调用 Gurobi 建模求解3.1 Solomn 数据集3.2 完整代码3.3 运行结果展示3.3.1 测试案例&#xff1a;c101.txt3.3.2 测试案例&#xff1a;r101.txt一、概述 1.1 VRP 问题 车辆路径规划问…

一场深度的IT效率革命:低代码市场加速嬗变

尽管IT技术支撑了全球的信息化浪潮&#xff0c;然而困扰行业已久的软件开发效率却难以像摩尔定律一样快速提升&#xff0c;甚至已经成为了一种瓶颈&#xff0c;在困扰着行业的继续发展。一边是码农们高喊着996的境况&#xff0c;另一边是程序员的生产力并没有用在更具价值的生产…

Qml学习——布局

最近在学习Qml&#xff0c;但对Qml的各种用法都不太熟悉&#xff0c;总是会搞忘&#xff0c;所以写几篇文章对学习过程中的遇到的东西做一个记录。 学习参考视频&#xff1a;https://www.bilibili.com/video/BV1Ay4y1W7xd?p1&vd_source0b527ff208c63f0b1150450fd7023fd8 目…