Android Kotlin中协程详解

博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家,
👉点击跳转到教程

前言
Kotlin协程介绍:
Kotlin 协程是 Kotlin 语言中的一种用于处理异步编程的机制。它提供了一种轻量级的线程替代方案,允许你以更简洁和可读的方式编写并发代码。

使用Kotlin协程需要引入Kotlin协程依赖包,这里引入的Kotlin核心依赖包,需要根据当前项目使用的Kotlin版本来引入,我使用的Kotlin版本为1.4.32所以引入的Kotlin核心依赖包版本为:1.4.3

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'

具体可以去到Maven Repository去查找使用对应的版本。

在这里插入图片描述
一、GloabalScope

1、使用GlobalScope构建协程。

		GlobalScope.launch {Log.d("协程 当前线程:", Thread.currentThread().name)}

输出日志

在这里插入图片描述

2、launch中的代码段是执行在子线程中的,如果需要在开启协程的时候指定线程,
可以设置Dispatchers参数值。下面以开启协程并使其在I/O线程中执行为例。

		GlobalScope.launch(Dispatchers.IO) {Log.d("Dispatchers.IO 当前线程:", Thread.currentThread().name)}

输出日志
在这里插入图片描述

3、取消协程 launch()返回一个Job对象,如果协程执行了一个耗时任务,如果耗时任务还未执行完,这是Activity被销毁,这是需要执行job.cancel(),来取消协程。终止后续代码的执行。

		val job = GlobalScope.launch(Dispatchers.IO) {Log.d("Dispatchers.IO 当前线程:", Thread.currentThread().name)}//取消协程应该放在恰当的位置job.cancel()

二、CoroutineScope
1、通过CoroutineScope创建协程在实际项目中,用的较为广泛。

		val job = Job()CoroutineScope(job).launch {//逻辑处理}job.cancel()

2、async,使用async来获取协程的执行结果。
详解async函数
aysnc函数同样可以构建一个协程作用域,并返回Deferred对象。但是与Coroutine-Scope函数不同的
是,async函数必须在协程作用域中才能调用

   		val job = Job()CoroutineScope(job).launch {//逻辑处理val result = async {//模拟耗时操作delay(3000)"操作成功"}.await()Log.d(TAG, result)}

输出日志,通过delay()函数,让协程延迟3秒执行。
实际使用过程中,可能会出现各种意外的情况,导致发生异常。这里举一个例子。
这里报的异常想必大家都知道 java.lang.ArithmeticException: divide by zero,不能除以0
但是我下面的做法并不能正确的捕获异常依然会报错,导致程序异常退出。

		//错误写法val job = Job()CoroutineScope(job).launch {try {//逻辑处理val result = async {//模拟耗时操作delay(3000)"操作成功" + 6 / 0}.await()Log.d(TAG, result)} catch (e: Exception) {e.printStackTrace()}}

这是因为在协程作用域外层是无法捕获到协程异常的,这是因为已
经超出了协程作用域的范围,try catch必须包裹ascync函数开启的协程作用域。

		val job = Job()CoroutineScope(job).launch {//逻辑处理val result = async {try {//模拟耗时操作delay(3000)"操作成功" + 6 / 0} catch (e: Exception) {"结果异常"}}.await()Log.d(TAG, result)}

3.await()方法,await()方法会阻塞当前协程(launch启动的外层协程),而不是 async 启动的内部协程,

		/**启动 launch 协程。在 launch 协程中,首先启动第一个 async 协程,开始耗时操作。调用 await() 时,launch 协程会被暂停,直到第一个 async 协程完成。之后,继续执行外层 launch 协程,并启动第二个 async 协程。调用第二个 async 的 await(),再次暂停外层的 launch 协程,直到第二个 async 协程完成。一旦两个 async 协程都完成,launch 协程继续执行剩余逻辑。*/val job = Job()CoroutineScope(job).launch {val startTime = System.currentTimeMillis()//逻辑处理val result = async {//模拟耗时操作delay(3000)"操作成功"}.await()//逻辑处理val result2 = async {//模拟耗时操作delay(3000)"获取成功"}.await()Log.d(TAG, "执行结果:$result - $result2")val endTime = System.currentTimeMillis()Log.d(TAG, "执行时间: ${endTime - startTime}")}

输出结果

在这里插入图片描述
针对上述情况,我们可以在用到执行结果的时候调用wait()方法,这样就可以让result和result2同时执行了。

		val job = Job()CoroutineScope(job).launch {val startTime = System.currentTimeMillis()//逻辑处理val result = async {//模拟耗时操作delay(3000)"操作成功"}//逻辑处理val result2 = async {//模拟耗时操作delay(3000)"获取成功"}Log.d(TAG, "执行结果:${result.await()} - ${result2.await()}")val endTime = System.currentTimeMillis()Log.d(TAG, "执行时间: ${endTime - startTime}")}

输出结果:

在这里插入图片描述
执行时间节省了3秒左右,因为程序同时调用了result和result2的await方法,这样result和result2相当于并行的关系,在实际项目中常有需要合并不同接口执行结果的需求,这时就 可以采用这种方式来提高运行效率。

三、withContext
1、通过withContext来构建协程作用域,withCotext是一个挂起函数。
首先来讲一下挂起函数。
在CoroutineScope(job).launch开启的协程中,通过会进行IO操作,或者网络请求的操作,为方便阅读通过会抽取到一个方法中,这里我声明了loadData()

		val job = Job()CoroutineScope(job).launch {loadData()}fun loadData() {delay(2000)Log.d(TAG, "--loadData--")}

delay(2000)这个函数会报一个错误,Suspend function ‘delay’ should be called only from a coroutine or another suspend function。意思就是挂起函数delay()应该在协程作用域,或者另一个挂起函数中被调用。因此这里的loadData()函数,必须加上suspend。
那么这里可能就有人要问了,这个挂起函数有什么用呢,在实际项目中,我们可以封装一些网络请求,IO操作等耗时的功能封装在挂起函数,这样别人看到之后也能明白,这些挂起函数是要在协程中进行使用的。
所以suspend在Kotlin协程中起到的仅仅是提醒作用。

2、withCotext函数用法

		val job = Job()CoroutineScope(job).launch {val result = withContext(Dispatchers.IO) {delay(2000)"获取成功"}Log.d(TAG, "$result")}

输出日志

在这里插入图片描述

withContext函数同样是一个挂起函数,需要在协程中或者另一个挂起函数中调用,withCotext函数会将最后一行执行结果作为返回值。

与async函数不同的是,withContext函数会强制要求传入一个线程参数,参数值类型有
Dispatchers.Default、Dispatchers.IO、Dispatchers.Main这三种,Dispatchers.Default常用于计算密集
型任务,Dispatchers.IO常用于网络请求、文件读写等操作,Dispatchers.Main则表示程序在主线程
中执行,所以当开启协程的时候,协程作用域中的代码不一定是执行在子线程的,这取决于这个线
程参数的值。
现在我们如何使用协程更优雅的操作UI呢
这里使用CoroutineScope开启Main协程,通过withContext开启I/O协程,当withContext协程作用域代码执行结束时,会继续回到Main协程执行UI的代码逻辑。示例代码如下:

		val job = Job()CoroutineScope(job).launch(Dispatchers.Main) {val result = getResult()showUI(result)val result2 = getResult2()showUI(result2)}private suspend fun getResult(): String {return withContext(Dispatchers.IO) {delay(2000)"操作成功"}}private suspend fun getResult2(): String {return withContext(Dispatchers.IO) {delay(4000)"获取成功"}}private fun showUI(result: String) {Log.d(TAG, "showUI: ")tv_result.text = result}

输出日志:
在这里插入图片描述
从上述代码中可以看出,即使程序需要多次切换协程,也不需要像使用线程一样层层嵌套,这样就
实现了使用协程更优雅地实现异步任务。

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

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

相关文章

《Python网络安全项目实战》

《Python网络安全项目实战》 项目1 Python 环境安装任务1.1 Windows上安装Python任务1.2 Ubuntu环境下安装Python 项目2 Python基础练习任务2.1 使用数据类型任务2.2 使用组合数据类型任务2.3 使用控制结构任务2.4 使用函数任务2.5 使用模块 项目3 处理文件中的数据任务3.1 读文…

雷赛L6N伺服驱动器基本参数设置——EtherCAT 总线型

1、指令脉冲设置 PA0.08代表电机转一圈,所需要的指令脉冲数,该值驱动器默认值为0,该值更改后断电重启后生效。 2、编码器反馈脉冲设置 PA0.11,代表编码器输出每转脉冲数,实际反馈的脉冲数做了4倍频处理,设…

MySql数据库中数据类型

本篇将介绍在 MySql 中的所有数据类型,其中主要分为四类:数值类型、文本和二进制类型、时间日期、String 类型。如下(图片来源:MySQL数据库): 目录如下: 目录 数值类型 1. 整数类型 2. …

【论文笔记】MLSLT: Towards Multilingual Sign Language Translation

🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: MLSLT: Towards Multiling…

系统架构设计师教程 第2章 2.6 计算机语言 笔记

2.6计算机语言 ★★★★☆ 2.6.1计算机语言的组成 计算机语言 (Computer Language) 是指用于人与计算机之间交流的一种语言,是人与计算机之间传递信息的媒介。 计算机语言主要由一套指令组成,指令一般包括表达式、流程控制和集合三大部分内容。 表达…

基于JSP的高校食堂食材选购管理系统【附源码】

基于JSP的高校食堂食材选购管理系统 效果如下: 系统首页界面 用户登录页面 食材信息页面 论坛交流界面 管理员登录界面 管理员功能主界面 食材信息管理界面 订单配送管理界面 用户功能主界面 商家功能主界面 司机功能主界面 研究背景 近年来互联网技术的发展使得…

新王Claude 3.5的6大应用场景

Anthropic AI深夜发布了备受期待的Claude 3.5系列更新,包括了全新升级的Claude 3.5 Sonnet和首发的Claude 3.5 Haiku。 Claude 3.5 Sonnet能够理解细微的指令和上下文,识别并纠正自身错误,还能从复杂数据中生成深入的分析和洞察。 结合最先进…

java项目之在线考试系统设计与实现(springboot)

风定落花生,歌声逐流水,大家好我是风歌,混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的在线考试系统设计与实现。项目源码以及部署相关请联系风歌,文末附上联系信息 。 项目简介: 基于JavaWeb技术…

PostgreSQL C++客户端API libpqxx的使用

PostgreSQL是一个先进的、开源的、免费的、功能强大的关系型数据库,缩写版是postgres。它使用一种客户端/服务器(C/S)的模型。一次PostgreSQL会话由下列相关的进程(程序)组成: (1).一个服务器进程,它管理数据库文件、接受来自客户端应用与数据…

C++研发笔记8——C语言程序设计初阶学习笔记6

在第一部分——课前准备的学习中,我就提到了学习C语言的过程中,练习是必不可少的环节,所以本篇笔记我们来进行记录我们学习《C语言程序设计初阶》阶段的第一篇练习文章。 题目一 下面哪个不是C语言内置的数据类型: A.char B.d…

mysql5.7.44 arm 源码编译安装

一、:下载源码:mysql官网:MySQL :: MySQL Downloads #####下载mysql安装包 : 网址:https://www.mysql.com/ 可在页面下载后上传或直接下载。 官网地址首页,拉到最底部,找到社区版本下载&#xf…

财务域——财务信息化

摘要 博文探讨了企业财务信息化相关内容。首先阐述了企业以创造价值为目标,涉及业务、管理和信息三大循环。业务循环涵盖获取 / 支付、转换、销售 / 收款等环节;管理循环包含计划、执行、控制与决策;信息循环强调数据的收集、处理、存储与输…

【Linux | IO多路复用】epoll的底层原理详解

epoll 是一种高效的 I/O 多路复用机制,广泛用于 Linux 系统中,用于处理大量并发的文件描述符。它比传统的 select 和 poll 方法具有更好的性能,特别是在处理大量并发连接时。 1.epoll的设计思路 epoll是在select 出现 N 多年后才被发明的&a…

week08 zookeeper多种安装与pandas数据变换操作-new

课程1-hadoop-Zookeeper安装 Ububtu18.04安装Zookeeper3.7.1 环境与版本 这里采用的ubuntu18.04环境的基本配置为: hostname 为master 用户名为hadoop 静态IP为 192.168.100.3 网关为 192.168.100.2 防火墙已经关闭 /etc/hosts已经配置全版本下载地址&#xff1…

软考(网工)——网络安全

文章目录 🕐网络安全基础1️⃣网络安全威胁类型2️⃣网络攻击类型 🕑现代加密技术1️⃣私钥密码/对称密码体制2️⃣对称加密算法总结3️⃣公钥密码/非对称密码4️⃣混合密码5️⃣国产加密算法 - SM 系列6️⃣认证7️⃣基于公钥的认证 🕒Hash …

MYSQL全局锁、标级锁、行级锁

一、全局锁 全局锁就是对整个数据库实例加锁。 MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新…

好/坏代码实例解读:图文并茂说明

我曾经在某处读到过一句话,基本上有以下内容: “现代世界许多人的生活都依赖于软件,例如控制大型商用客机飞行系统的软件,但软件开发领域大多不受监管。任何人都可以成为自学成才的软件开发人员,并且没有像其他高风险…

python爬虫——Selenium的基本使用

目录 一、Selenium的介绍 二、环境准备 1.安装Selenium 2.安装WebDriver 三、元素定位 1.常用定位元素的方法 2. 通过指定方式定位元素 四、窗口操作 1.最大化浏览器窗口 2.设置浏览器窗口大小 3.切换窗口或标签页 切换回主窗口 4. 关闭窗口 关闭当前窗口 关闭所…

Mkdm的51单片机学习日记:实时时钟DS1302

15.2 SPI时序初步认识 单片机常用的通信协议有三种:SPI,UART,I2C SPI:Serial Peripheral Interface 串行外围设备接口,是一种全双工,同步的通信总线 常用于单片机与EEPROM,FLASH,…

如何使用JMeter进行性能测试的保姆级教程

性能测试是确保网站在用户访问高峰时保持稳定和快速响应的关键环节。作为初学者,选择合适的工具尤为重要。JMeter 是一个强大的开源性能测试工具,可以帮助我们轻松模拟多用户场景,测试网站的稳定性与性能。本教程将引导你通过一个简单的登录场…