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

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}

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

相关文章:

Android Kotlin中协程详解

博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家, 👉点击跳转到教程 前言 Kotlin协程介绍: Kotlin 协程是 Kotlin 语言中的一种用于处理异步编程的机制。它提供了一…...

【webpack学习】

webpack由于历史包袱导致复杂,只要把握关键流程即可 webpack的主要流程loader plugin难点:HMR / 懒加载 原理webpack 的优化手段 构建工具对比 webpack :可以打包任何资源,配置略复杂,适合项目开发rollup&#xff1…...

H5实现PDF文件预览,使用pdf.js-dist进行加载

H5实现PDF文件预览,使用pdf.js-dist进行加载 一、应用场景 在H5平台上预览PDF文件是在原本已经开发完成的系统中新提出的需求,原来的系统业务部门是在PC端进行PDF的预览与展示,但是现在设备进行了切换,改成了安卓一体机进行文件…...

面试域——面试系统工程

摘要 1. 当前就业面试场景 1.1. 招聘市场的“551 定律” 你知道招聘市场的“551 定律”吗? 551 定律:每一层筛选环节都会有百分之十的折损率。一个岗位从接收简历到发下 Offer 至少要筛选 500 份左右的简历、面试 50 人左右、只有 5 人左右通过面试&am…...

PHP-FPM 性能配置优化

4 核 8 G 服务器大约可以开启 500 个 PHP-FPM,极限吞吐量在 580 qps (Query Per Second 每秒查询数)左右。 Nginx php-fpm 是怎么工作的? php-fpm 全称是 PHP FastCGI Process Manager 的简称,从名字可得知&#xff…...

渗透测试-百日筑基—SQL注入篇时间注入绕过HTTP数据编码绕过—下

day8-渗透测试sql注入篇&时间注入&绕过&HTTP数据编码绕过 一、时间注入 SQL注入时间注入(也称为延时注入)是SQL注入攻击的一种特殊形式,它属于盲注(Blind SQL Injection)的一种。在盲注中,攻击…...

Unity - UGUI动静分离

原理:UGUI 是基于Canvas来进行合并计算的 1.不同Cavans的UI元素,是无法合批渲染,无法实现同一个drawcall 2. 每次合批的时候,会合并计算Canvas下所有的UI元素 , 具体流程: Step1: 对Cavans下所有的UI元素进行合批计算 Step2: …...

arm 体系架构-过程调用约定

ref: ARM体系结构学习笔记:过程调用标准AAPC、 ARM32调用约定、ARM64调用约定_arm64 传参 结构体-CSDN博客 ARM软件逆向工程入门 01 - ARM调用约定(Calling Convention)_armv7函数调用约定-CSDN博客 ARM学习(17&…...

STM32基于LL库的USART+DMA使用

时隔两年半再次更新LL库,本次带来USART DMA 实现接收不定长。 1、开发思路 使用USART DMA接收不定长的功能的思路是:借助USART的空闲中断、DMA发送完成中断。 打开F103的手册可得知,USART的空闲中断触发条件是在接收完成后触发&#xff0…...

设计模式06-结构型模式1(适配器/桥接/组合模式/Java)

#1024程序员节|征文# 4.1 适配器模式 结构型模式(Structural Pattern)的主要目的就是将不同的类和对象组合在一起,形成更大或者更复杂的结构体。结构性模式的分类: ​ 类结构型模式关心类的组合,由多个类…...

【损害和风险评估&坑洼】路面坑洼检测系统源码&数据集全套:改进yolo11-DCNV3

改进yolo11-DLKA等200全套创新点大全:路面坑洼检测系统源码&数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.10.24 注意:由于项目一直在更新迭代,上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或者视频可…...

GenAI 生态系统现状:不止大语言模型和向量数据库

自 20 个月前 ChatGPT 革命性的推出以来,生成式人工智能(GenAI)领域经历了显著的发展和创新。最初,大语言模型(LLMs)和向量数据库吸引了最多的关注。然而,GenAI 生态系统远不止这两个部分&#…...

gitlab 配置ssh keys

settings -- 终端配置: git config --global user.email "yxthotmail.cm" 配置gitlab 账号邮箱 git config --global user.name "xt.yao" 配置gitlab账号用户名 生成SSH key,输入命令ssh-keygen -t rsa,一直按回车…...

小程序开发实战:PDF转换为图片工具开发

目录 一、开发思路 1.1 申请微信小程序 1.2 编写后端接口 1.3 后端接口部署 1.4 微信小程序前端页面开发 1.5 运行效果 1.6 小程序部署上线 今天给大家分享小程序开发系列,PDF转换为图片工具的开发实战,感兴趣的朋友可以一起来学习一下&#xff01…...

我有两台120kw充电桩一天能赚多少钱

(当前是理想状态下,当然还要看场地费用,还有物业,变压器,等等) ———————————————————— ———————————————————— 要计算两台120kW充电桩能赚多少钱,我们…...

深入了解 Android 中的命名空间:`xmlns:tools` 和其他常见命名空间

在 Android 开发中,xmlns (.xml的namespace)命名空间是一个非常重要的概念。通过引入不同的命名空间,可以使用不同的属性来设计布局、设置工具属性或者支持自定义视图等。除了 xmlns:tools 以外,还有很多常见的命名空间…...

stable-zero123模型构建指南

一、介绍 stabilityai出品,能够对有简单背景的物体进行三维视角图片的生成,简单来说也就是通过调整变换观察的视角生成对应视角的图片。 本项目通过comfyui实现。 二、容器构建说明 1. 部署ComfyUI (1)使用命令克隆ComfyUI g…...

算法题解记录32+++最长连续序列(百题筑基)

你们好,我是蚊子码农,好久不见。由于秋招求职的繁琐事情,我有很长一段时间没更新博客,希望我的粉丝们能够谅解。 秋招我拿到了一些offer,最终决定去一个主要做“网络安全”业务的公司工作,也许明天会更好&a…...

全球知名度最高的华人起名大师颜廷利:世界顶级思想哲学教育家

全国给孩子起名最好的大师颜廷利教授在其最新的哲学探索中,提出了《升命学说》这一前沿理论观点,该理论不仅深刻地回应了古今中外众多哲学流派和思想体系的精髓,还巧妙地融合了实用主义、理想主义以及经验主义的核心理念。通过这一独特的视角…...

Flink Rest API

REST API | Apache Flink Flink官网API 通过curl 或者Rest API工具测试web UI对应的接口返回信息 Flink 提交yarn任务 ./bin/flink run -t yarn-per-job historyServer ../bin/historyserver.sh start...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

NFT模式:数字资产确权与链游经济系统构建

NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案

引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC&#xf…...