kotlin中协程相关

协程

  • 用同步的方式写出异步的效果
  • 协程最重要的是通过非阻塞挂起和恢复实现了异步代码的同步编写方式
  • 挂起函数(suspend)不一定就是在子线程中执行的,但是通常在定义挂起函数时都会为它指定其他线程,这样挂起才有意义
  • 解决多层嵌套回调

协程不是线程,是基于线程封装的库,可以使用协程库提供的API方便的灵活的指定协程中代码执行的线程、切换线程,但不需要接触线程Thread类。类似于Android的AsyncTask或者RxJava的Schedulers,都解决了异步线程切换的问题,然而协程最重要的是通过非阻塞挂起和恢复实现了异步代码的同步编写方式,把原本运行在不通线程的代码写在一个代码块{}里,开起来就像是同步代码。

launchasync之间的区别

launch是一种适用于“发射并忘记”场景的协程构建器,当你不需要等待协程的结果时,它非常有用。它允许你在后台异步执行任务,而不会阻塞主线程,从而提高应用的响应性。

示例:使用launch

fun main() {println("Before launch")// 启动一个协程GlobalScope.launch {delay(1000)println("Inside launch")}println("After launch")Thread.sleep(2000)
}

在上面的示例中,我们使用launch关键字在GlobalScope中启动了一个协程。协程通过delay()函数暂停了1000毫秒,然后打印了"Inside launch"。同时,主线程继续执行。输出结果为:Before launch      After launch     Inside launch

async是一种用于异步执行任务并获取其结果的协程构建器。它返回一个Deferred<T>对象,表示将来可用的值

示例:使用async并发进行网络请求

suspend fun fetchDataFromAPI(url: String): String {// 执行网络请求或其他耗时操作return apiService.fetchData(url)
}suspend fun fetchMultipleData() {val deferredData1 = GlobalScope.async(Dispatchers.IO) {fetchDataFromAPI("https://api.example.com/data1")}val deferredData2 = GlobalScope.async(Dispatchers.IO) {fetchDataFromAPI("https://api.example.com/data2")}val data1 = deferredData1.await()val data2 = deferredData2.await()// 处理获取到的数据```kotlinprocessData(data1, data2)
}

在这个示例中,我们使用async来并发地从多个URL获取数据。每个网络请求被封装在一个单独的async块中,它返回一个Deferred<String>对象。然后我们使用await()来在结果可用时获取结果。获取到数据后,我们可以根据需要进行进一步处理。

总结选择launchasync的关键考虑因素:

  • 当你想要执行一个异步任务而不需要等待结果时,例如进行网络请求或执行后台操作时,使用launch

  • 当你需要并发地执行多个异步任务并获取它们的结果以进行进一步处理时,例如并行网络请求或计算时,使用async

  • 要注意选择合适的上下文来启动协程,以确保正确的线程管理。对于与UI相关的操作,切换到Dispatchers.Main上下文来更新UI。

  • 避免使用长时间运行的操作阻塞主UI线程。使用协程将这些任务转移到后台线程,从而确保响应性用户界面

suspend:withContext(Dispatchers.IO)异步线程

MainScope   需要销毁在onDestroy()方法中:main.cancel()

GlobalScope 全局作用域 默认是异步线程Dispatchers.IO

viewModelScope.launch 默认是主线程Dispatchers.Main

一个页面请求多个接口示例

class SystemViewModel : BaseViewModel() {private val remoteRepository: SystemRemoteRepository by lazy {SystemRemoteRepository()}val page = MutableLiveData<Pagination<Article>>()fun getArticleList() {viewModelScope.launch { //主线程开启一个协程// 网络请求:IO线程val tree: ApiResult<MutableList<Tree>> =RetrofitClient.apiService.getTreeByCoroutines()// 主线程val cid = tree?.data?.get(0)?.idif (cid != null) {// 网络请求:IO线程val pageResult: ApiResult<Pagination<Article>> =RetrofitClient.apiService.getArticleListByCoroutines(0, cid)// 主线程page.value = pageResult.data!!}}}
}/**接口定义,Retrofit从2.6.0版本开始支持协程*/
interface ApiService {/*获取文章树结构*/@GET("tree/json")suspend fun getTreeByCoroutines(): ApiResult<MutableList<Tree>>/*根据数结构下某个分支id,获取分支下的文章*/@GET("article/list/{page}/json")suspend fun getArticleListByCoroutines(@Path("page") page: Int,@Query("cid") cid: Int): ApiResult<Pagination<Article>>
}
在定义接口时,方法前加了个 suspend 关键字,调用接口的时候用viewModelScope.launch {} 包裹。既然可以运行成功,就说明请求接口并不是在主线程中进行的,然而有的同学不信,他在getArticleList() 方法中的任意位置通过 Thread.currentThread() 打印的结果都Thread[main,5,main],这不就是在主线程中调用的吗?上述协程中的代码是在主线程执行没错,但是接口请求的方法却是在子线程中执行的。
原因就在于我们定义接口的时候使用了suspend 关键字,它的意思是挂起、暂停,函数被加了这个标记就称它为挂起函数,需要注意的是,suspend 关键字并没有其他重要的作用,它仅仅标识某个函数是挂起函数,可以在函数中调用其他挂起函数,但是只能在协程中调用它。所以上面两个接口都被定义为挂起函数了,挂起函数只能在协程中调用,那谁是协程?
其实在 kotlin 协程库中是有一个类 AbstractCoroutine 来表示协程的,这个抽象类有很多子类代表不同的协程,但是这些子类都是private 的,并没有暴露给我们,所以你在其他文章中看到别人说
viewModelScope.launch{} 包裹起来的闭包 ( 代码块 ) 就是协程也没问题,但这个代码块的真正意义是协程需要执行的代码。当在协程中调用到挂起函数时,协程就会在当前线程(主线程)中被挂起,这就是协程中著名的 非阻塞式挂起,主线程暂时停止执行这个协程中剩余的代码,注意:暂停并不是阻塞等待(否则会ANR ),而是主线程暂时从这个协程中被释放出来去处理其他 Handler 消息,比如响应用户操作、绘制View 等等。
那挂起函数谁执行?这得看挂起函数内部是否有切换线程,如果没有切换线程当然就是主线程执行了,所以挂起函数不一定就是在子线程中执行的,但是通常在定义挂起函数时都会为它指定其他线程,这样挂起才有意义。比如上面定义的suspend 的请求接口, Retorift 在执行请求的时候就切换到了子线程并挂起主线程,当请求完成(挂起函数执行完毕)返回结果时,会通知主线程:我该干的都干完了,下面的事你接着干吧,主线程接到通知后就会拿到挂起函数返回的结果继续执行协程里面剩余的代码,这叫做协程恢复(resume) 。如果又遇到挂起函数就会重复这个过程,直到协程中的代码被执行完。
通过协程可以彻底去除回调,使用同步的方式编写异步代码。什么是同步调用?调用一个方法能直接拿到方法的返回值,尽管这个方法是耗时的、在其他线程执行的,也能直接得到它的返回值,然后再执行下面的代码,协程不是通过等待的方式实现同步,而是通过非阻塞挂起实现看起来同步的效果。

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

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

相关文章

《21天学通C++》阶段性成果测试题——hstring(手写string类)

hstring就是自己创建一个字符串操作类,实现对字符串的增删改查&#xff0c;而不是调用string类。总体考察了类的使用,缓冲区考察了指针和数组的使用、增删改查、考察编码思维、考察了类的重载。 完整代码在最下面 要求&#xff1a; 1.设置缓冲区&#xff1a; 存储数据的时候使…

蓝桥杯备战11.歌唱比赛

P5738 【深基7.例4】歌唱比赛 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<bits/stdc.h> #define endl \n #define int long long using namespace std; const int N 2e710,M 1e310; int a[N],sum[N];signed main() {//std::ios::sync_with_stdio(0),cin.…

VScode查看以十六进制查看文件的插件说明

找到插件并下载 打开指定的文件 选择打开方式即可 结果如下

C++/Qt 小知识记录6

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识6 dumpbin工具查看库导出符号OSGEarth使用编出的protobuf库&#xff0c;报错问题解决VS2022使用cpl模板后&#xff0c;提示会乱码的修改设置QProcess调用cmd.exe执行脚本QPainterPath对线段描边处理…

英文文本标点恢复

文章目录 一、安装 rpunct二、使用三、下载模型时报错1、报错详情2、报错原因3、解决方案 四、程序运行时报错1、报错详情2、报错原因3、解决方案 五、修改默认缓存路径 一、安装 rpunct pip install rpunct 相关依赖包信息&#xff1a; langdetect1.0.9 pandas1.2.4 simpletr…

Java入门最小必要知识:变量及其本质

编程语言是与计算机交流的桥梁&#xff0c;而在编程世界中&#xff0c;变量是这座桥上不可或缺的砖石。 从本质上&#xff0c;可以把复杂的编程工作简化为两件事&#xff1a; ①定义变量②操作变量 可见&#xff0c;变量之于编程的重要性。 对于Java开发者&#xff0c;理解…

阿里云 物联网平台 MQTT连接、数据传输

阿里云 物联网平台 MQTT连接、数据传输 1、设备连接阿里云 2、多设备之前的通信、数据流转 3、设备数据来源的读取。 基于C# winform 开发上位机&#xff0c;读取设备、仪器、MES或者电子元器件的数据&#xff0c;MQTT传输至阿里云平台&#xff0c;可视化界面构建界面&#…

华为OD介绍

概念 华为OD是华为提出的一种新的用工方式&#xff0c;其全称是Outsourcing Dispacth&#xff0c;也可以简写为ODP&#xff0c;是华为和北京外企德科人力资源服务上海有限公司联合招聘的简称。华为OD岗位属于华为外包员工的一种&#xff0c;仅限于软件研发类岗位&#xff0c;类…

1065: 无向图的连通分量计算

解法&#xff1a; dfs求连通性 1.设节点表vis[] 2.遍历节点表dfs标记&#xff0c;每次得到一个连通分量 #include<iostream> #include<vector> using namespace std; int arr[100][100]; void dfs(vector<bool>& vis, int v) {//不用终止条件&#x…

StringRedisTemplate使用

文章目录 一&#xff0c;StringRedisTemplate介绍二&#xff0c;StringRedisTemplate使用1.字符串&#xff08;String&#xff09;&#xff1a;2.哈希&#xff08;Hash&#xff09;&#xff1a;3.列表&#xff08;List&#xff09;&#xff1a;4.集合&#xff08;Set&#xff0…

省级生活垃圾无害化处理率面板数据(2004-2022年)

01、数据简介 生活垃圾无害化处理率是指经过处理的生活垃圾中&#xff0c;达到无害化标准的垃圾所占的比例。这一指标是衡量城市垃圾处理水平的重要标准&#xff0c;反映了城市对垃圾进行有效管理和处理的能力。 生活垃圾无害化处理的主要方式包括生活垃圾焚烧、生活垃圾卫生…

金三银四面试题(二十八):观察者模式知多少?

什么是观察者模式 观察者模式&#xff08;Observer Pattern&#xff09; 是一种设计模式&#xff0c;它定义了一种一对多的关系&#xff0c;让多个观察者对象能够同时监听一个主题对象。当主题对象的状态发生变化时&#xff0c;会通知所有观察者对象&#xff0c;使它们能够作出…

Sass:强大而灵活的CSS预处理器详解

Sass&#xff1a;强大而灵活的CSS预处理器详解 在前端开发的世界里&#xff0c;CSS&#xff08;层叠样式表&#xff09;作为样式描述语言&#xff0c;为我们提供了丰富的样式定义和布局方式。然而&#xff0c;随着项目规模的不断扩大和复杂度的提升&#xff0c;原生CSS的编写和…

C++:完美转发(二)(std::forward)

一、RVO优化和std::move、std::forward 以下是一个综合性的例子&#xff1a; #include <iostream> #include <memory> #include <ostream> using namespace std;// 1. 针对右值引用实施std::move&#xff0c;针对万能引用实施std::forward class Data {};c…

react之Reducer和Context的联合使用

第三章 - 状态管理 使用 Reducer 和 Context 拓展你的应用 Reducer 可以整合组件的状态更新逻辑。Context 可以将信息深入传递给其他组件。你可以组合使用它们来共同管理一个复杂页面的状态。 结合使用 reducer 和 context 在 reducer 介绍 的例子里面&#xff0c;状态被 r…

如何修复Windows中的“无Internet,安全”错误?这里有详细步骤

序言 在Windows计算机上连接到互联网非常容易,但是,当你尝试连接到网络时,Windows有时可能会显示消息“无Internet,安全”。此消息的确切含义是什么?如何修复?以下是你需要了解的所有信息。 为什么Windows显示“无Internet,安全”消息 “无Internet,安全”消息是一个…

简约在线生成短网址系统源码 短链防红域名系统 带后台

简约在线生成短网址系统源码 短链防红域名系统 带后台 安装教程&#xff1a;访问 http://你的域名/install 进行安装 源码免费下载地址抄笔记 (chaobiji.cn)https://chaobiji.cn/

图像分割各种算子算法-可直接使用(Canny、Roberts、Sobel)

Canny算子&#xff1a; import numpy as np import cv2 as cv from matplotlib import pyplot as pltimg cv.imread("../test_1_1.png") edges cv.Canny(img, 100, 200)plt.subplot(121),plt.imshow(img,cmap gray) plt.title(Original Image), plt.xticks([]), …

MySQL数据库之UNION 和JOIN连接的区别?

UNION和JOIN连接是用于合并表中数据的两种不同方法。 1、JOIN连接&#xff1a; 用于在查询中将两个或多个表中的行基于它们之间的关联条件进行匹配。JOIN操作允许您将来自不同表的相关数据组合到一起&#xff0c;以便一次性检索所有相关信息。JOIN操作通常涉及使用ON子句指定…

电文加密(C语言)

一、题目说明&#xff1b; 即第1个字母变成第26个字母&#xff0c;第i个字母变成第(26 - i 1)个字母&#xff0c;非字母字符不变。 二、N-S流程图&#xff1b; 三、运行结果&#xff1b; 四、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h&g…