Android --- Kotlin学习之路:协程的使用,什么是协程,为什么要用协程?(学习笔记)

Kotlin 协程(coroutine)学习
以下干货满满,掌握以下内容一定会对你在项目开发中有所帮助,记得收藏!!!

文章目录

    • 什么是协程,为什么要用协程?
    • 挂起函数挂起的是什么?
    • 挂起函数中的suspend 关键字的作用是什么?
    • 如果你想在协程中执行串行的代码,而不是并行的,怎么处理?
    • 怎么样写一个自定义挂起函数?
    • 并行协程的启动和交互
    • 什么是耗时操作?
    • 挂起和阻塞的区别,什么叫挂起,什么叫阻塞?
    • 协程所使用的调度器
    • 定义协程必须指定其 CoroutineScope,常用的相关API有:
    • 协程的启动
    • 协程的启动模式(指定协程启动之后的一些行为)
    • 协程的作用域构建器
    • Job对象
    • CPU密集型任务的取消
    • 协程取消的副作用
    • 超时任务怎么处理

什么是协程,为什么要用协程?

协程是基于线程,它是轻量级的线程
java用的是线程,kotlin用的是协程,协程是个并发管理工具,定位跟线程其实是一样的。
其实就是把java的线程包了一层。之前我们做网络请求的时候,想把网络请求的结果响应在主线程中,应该怎么写?
一般情况下我们会在主线程去开启一个子线程发起网络请求,然后将请求的结果在主线程显示
比如Retrofit,会帮我们实现自动在子线程去发起网络请求,不用我们自己new Thread,然后
会把结果通过onResponse的形式传递给我们,这个时候Retrofit也帮我们切到了主线程,而协程并不需要写回调了。
另外,比如我们想要先开启两个并行协程,然后需要最终合并到主线程,协程是实现是最简单的。

interface ApiService {@GET(value = "posts/1")fun queryUser(@Query(value = "userId", encoded = true) userId: String) : Call<UserResponse>@GET(value = "user")suspend fun getUser(@Query(value = "userid", encoded = true) username:String) :UserResponse
}

老的写法:

// Retrofit 请求
val create = Retrofit.create(ApiService::class.java)
create.queryUser("1").enqueue(object : Callback<UserResponse> {override fun onResponse(call: Call<UserResponse>, response: Response<UserResponse>) {if (response.isSuccessful) {val body = response.body()body?.let {Log.i("Retrofit", "get success : $it")}}}override fun onFailure(call: Call<UserResponse>, t: Throwable) {Log.e("Retrofit", "get onFailure : ${t.message}")}
})

协程的写法:

CoroutineScope(Dispatchers.Main).launch { // 主线程开启一个协程val create = Retrofit.create(ApiService::class.java)val user = create.getUser("zhangqi") // 这里调用的是一个挂起函数,挂起函数会在后台执行,原理是协程的Dispatchers.Main自己有线程池// 这一行可以做页面刷新,这行操作自动在主线程中执行,原理是,挂起函数会调用handler.post切换到主线程的
}

挂起函数挂起的是什么?

挂起的是协程,挂起之后,协程就会脱离当前线程,等待挂起函数执行完成之后再切回来

挂起函数中的suspend 关键字的作用是什么?

提醒函数调用者,我是一个耗时函数,需要放在后台运行,请在协程中调用我
suspend 只是提醒

如果你想在协程中执行串行的代码,而不是并行的,怎么处理?

需要使用withContext

CoroutineScope(Dispatchers.Main).launch {launch {println("--1-- ${Thread.currentThread().name}")}println("--2-- ${Thread.currentThread().name}")
}
上面的代码输出结果:
--2-- main
--1-- main

那如果我们想要按照顺序输出,就需要这样写

CoroutineScope(Dispatchers.Main).launch {withContext(Dispatchers.IO) {println("--1-- ${Thread.currentThread().name}")}println("--2-- ${Thread.currentThread().name}")
}
输出结果:
--1-- DefaultDispatcher-worker-1
--2-- main

因为withContext将线程切到了IO线程,所以后面的操作要等待withContext里面的内容执行完才能执行

怎么样写一个自定义挂起函数?

本质上没有自定义挂起函数,就是使用suspend关键字,
然后用挂起函数withContext(){}将你的耗时内容包裹起来

并行协程的启动和交互

lifecycleScope.launch {// deferred1 和 deferred2 并行val deferred1 = async {println("Test1 ${Thread.currentThread().name}") }val deferred2 = async {println("Test2 ${Thread.currentThread().name}") }showContributors(deferred1.await() + deferred2.await()) // 将上面两个协程的结果合并
}

什么是耗时操作?

文件读写,网络请求,等待操作(delay(10))等等,都是耗时操作

挂起和阻塞的区别,什么叫挂起,什么叫阻塞?

挂起就相当于delay(12000)
阻塞就相当于Thread.sleep(12000)
挂起之后你可以干其他事,但是阻塞之后你就要等,不能干其他事
什么叫挂起:当前协程不再占用它正在工作的这个线程

协程所使用的调度器

Dispatcher.Main 主线程,底层还是用原生handler.post()方法切到主线程的
Dispatcher.IO 非主线程 ,底层有自己的Executor管理
Dispacther.Default 非主线程,底层有自己的Executor管理
Dispacther.Unconfiend 基本不会用到

DEFAULT和IO的区别:
DEFAULT 的线程数量是CPU的核心数相等,面向计算密集型任务
IO 是固定的64个线程的线程池,面向I/O密集型型任务(读写文件,网络访问),CPU基本不工作,I/O的磁盘在做的

协程能够通过挂起函数实现切换线程之后切回来

定义协程必须指定其 CoroutineScope,常用的相关API有:

GlobalScope,生命周期是process级别的,顶级的,即使Activity或Fragment已经被销毁了,协程仍然在执行
MainScope, 在Activity中使用,可以在onDestory()中取消协程
viewModelScope,只能在ViewModel中使用,绑定ViewModel的生命周期
lifecycleScope,只能在Activity,Fragment中使用,会绑定Activity和Fragment的生命周期 ,会自动在onDestory 调用自己的cancel()方法取消

协程的启动

通过launch和async构建器启动协程
我们可以用async先启动一个协程,然后在别的协程中通过.await()获取它的结果

lifecycleScope.launch {// deferred1 和 deferred2 并行val deferred1 = async {println("Test1 ${Thread.currentThread().name}") }val deferred2 = async {println("Test2 ${Thread.currentThread().name}") }showContributors(deferred1.await() + deferred2.await()) // 将上面两个协程的结果合并
}

通过join和await等待作业
launch和async的区别,launch 返回的是一个Job对象,async返回的是一个Defferd对象,Defferd本质也是一个Job
launch常用于不需要返回结果的并发任务,async则常用在需要返回结果的并发任务中

val scope = CoroutineScope(Dispacther.Default)
scope.launch {}

协程的启动模式(指定协程启动之后的一些行为)

DEFAULT:协程创建后,立即开始调度,在调度前如果协程被取消,其将直接进入取消响应的状态
ATOMIC:协程创建后,立即开始调度,协程执行到第一个挂起点之前不响应取消
LAZY:只有协程被需要时,包括主动调用协程的start、join或者await等函数时才开始调度,如果调度前就被取消,那么协程将直接进入异常结束状态
UNDESPATCHED:协程创建后立即在当前函数调用栈中执行,直到遇到第一个挂起的点

val job = async(context = Dispacther.IO, start = CoroutineStart.UNDESPATCHED){println("thread"&{Thread.currentThread().name})
} 
//这段代码输出的是主线程

协程的作用域构建器

coroutineScope 和 runBlocking
runBlocking 是常规函数,会阻塞线程,coroutineScope是挂起函数。
coroutineScope 一个协程失败了,所有其他其他兄弟协程也会被取消
supervisorScope 一个协程失败了,不会影响其他协程的执行
coroutineScope 和 runBlocking会等待所有的字协程执行完毕,这个作用域才会结束

Job对象

负责管理协程的生命周期
新创建(New)活跃(Active)完成中(Completing)已完成(Completed)取消中(Cancelling)已取消(Cancelled)

CPU密集型任务的取消

要通过isActive ensureActive() yield 取消

协程取消的副作用

如果在取消协程之后做了一些释放资源的操作,那么就坏菜了。我们可以通过try{}finally{在这里面释放资源,这里的东西一定执行}
还可以用use函数,use函数内部会自己close()资源

超时任务怎么处理

val result = withTimeoutOrNull(1300) {repeat(1000) { i ->println("job: I'm sleeping &i")delay(500L)}"Done"
}?: "Jack"

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

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

相关文章

Svelte与Vue:框架性能与设计理念的比较

Svelte 和 Vue.js 都是现代前端框架&#xff0c;旨在简化 Web 开发并提高应用程序的性能。虽然它们都提供了构建用户界面的工具&#xff0c;但在设计理念、编译过程、运行时开销和性能方面存在显著差异。 Svelte 框架的特点 Svelte 的核心理念是在构建阶段尽可能多地完成工作…

JavaWeb JavaScript ① JS简介

目录 一、HTML&CSS&JavaScript的作用 二、前后端关联标签——表单标签 1.form标签 2.input标签 3.get/post提交的差异 4.表单项标签 5.布局相关标签 块元素——div 行内元素——span 三、CSS 1.CSS引入方式 方式1 行内式 方式2 内嵌式 方式3 外部样式表 2.CSS选择器 元…

【c++】用c++类做一个猜数字游戏

目录 源码: 想法: 可以改进的地方: 源码: #include<iostream> #include<ctime> #include<cstdlib> #include<string>using std::cout; using std::endl; using std::cin;class player { private:int card;bool viewable; public:player(): card…

Java基础编程500题——String

&#x1f4a5; 该系列属于【Java基础编程500题】专栏&#xff0c;如您需查看Java基础的其他相关题目&#xff0c;请您点击左边的连接 目录 1. 将字符串"Hello World"中的所有小写字母转换成大写字母。 2. 将两个字符串"Hello"和"World"拼接。 …

Zabbix监控介绍与部署

目 录 一、zabbix介绍和架构 1.1 zabbix介绍 1.2 为什么需要监控 1.3 需要监控什么 二、zabbix使用场景与系统概述 2.1 zabbix的功能 2.2 zabbix架构 2.3 Zabbix术语 三、编译安装zabbix 3.1 安装依赖环境 3.2 建立管理用户 3.3 准备源码包&#xff0c;解压包 3.…

082、Python 读文本文件

在Python中读取txt文本文件可以通过内置的open()函数结合file对象的read(), readline(), readlines()等方法实现。 1. 使用read()方法 read()方法会读取文件的全部内容&#xff0c;并将其作为一个字符串返回。 # 打开文件并读取全部内容with open(Resources/雨巷.txt, r, en…

Vue中Key的作用

在Vue中&#xff0c;Key的作用主要体现在以下几个方面&#xff1a; 1. 唯一标识列表元素 Key是Vue中用于唯一标识列表元素的特殊属性。在使用v-for指令渲染列表时&#xff0c;每个列表项都应该拥有唯一的key&#xff0c;这样Vue就能准确地追踪每个节点的身份&#xff0c;从而…

linux中当前目录、上级目录、上上级目录表示方法

1&#xff0c;cd [目录名]&#xff1a;表示进入某个目录 . &#xff1a;代表当前的目录&#xff0c;也可以使用 ./ 来表示&#xff1b;(一个点表示当前目录) . . &#xff1a;代表上一层目录&#xff0c;也可以 ../ 来代表。(两个点表示当前目录的上一层目录) ../..…

封装网络请求 鸿蒙APP HarmonyOS ArkTS

一、效果展示 通过在页面直接调用 userLogin(params) 方法&#xff0c;获取登录令牌 二、申请网络权限 访问网络时候首先需要申请网络权限&#xff0c;需要修改 src/main 目录下的 module.json5 文件&#xff0c;加入 requestPermissions 属性&#xff0c;详见官方文档 【声明权…

鸿蒙 next 5.0 版本页面跳转传参 接受参数 ,,接受的时候 要先定义接受参数的类型, 代码可以直接CV使用 [教程]

1, 先看效果 2, 先准备好两个页面 index 页面 传递参数 import router from ohos.routerEntry Component struct Index {Statelist: string[] [星期一, 星期二,星期三, 星期四,星期五]StateactiveIndex: number 0build() {Row() {Column({ space: 10 }) {ForEach(this.list,…

【Git远程操作】向远程仓库推送 | 拉取远程仓库

目录 1.向远程仓库推送 ​1.1本地仓库的配置 1.2remote-gitcode本地仓库 1.3推送至远程仓库 2.拉取远程仓库 现阶段以下操作仅在master主分支上。 1.向远程仓库推送 工作区☞add☞暂存区☞commit☞本地仓库☞推送push☞远程仓库注意&#xff1a;本地仓库的某个分支 ☞推…

《Techporters架构搭建》-Day01 第一个RESTful API接口

微服务架构搭建 搭建微服务架构分析一下项目的build.gradle添加Demo接口 搭建微服务架构 首先搭建系统管理模块&#xff0c;模块结构如下 tps-cloud └── tps-system -- 系统管理模块└── tps-system-api -- 系统管理模块公共api模块└── tps-system-biz -- 系统管理模…

单片机设计_自行车码表(AT89C51, LCD1602, DS1302,霍尔传感器)

想要更多项目私wo!!! 一、电路设计 系统采用51单片机LCD1602液晶DS1302时钟模块霍尔传感器电机按键模块蜂鸣器报警模块设计而成。 产品自带单片机上电复位电路、手动复位电路&#xff08;复位按键&#xff09;、晶振电路&#xff08;给单片机提供时钟周期&#xff09;。 …

Zabbix介绍和架构

目录 一.Zabbix简介 1.为什么需要监控 2.需要监控什么 3.常见的监控工具 4.Zabbix使用场景及系统概述 5.Zabbix 架构 6.Zabbix工作流程 7.Zabbix 术语 二. 部署安装zabbix 三.zabbix 配置文件 一.Zabbix简介 1.为什么需要监控 运维行业有句话:“无监控、不运维”&am…

AGV平面坐标系变换公式及实例

1、AGV坐标系简介 如上图&#xff0c;小车前后对角是有激光雷达的&#xff0c;其坐标系称为激光坐标系&#xff0c;采用极坐标系体现。中间为车体坐标系&#xff0c;激光坐标系相对于车体坐标系关系不变&#xff1b;左下角是地图坐标系&#xff0c;小车扫图后&#xff0c;建立的…

Java开发如何短时间准备 Java 面试?

发现一个问题&#xff0c;Java开发如何短时间准备 Java 面试&#xff1f; 本科应届毕业生&#xff0c;打算玩命一个月&#xff0c;争取三月份参加面试&#xff08;面正式岗&#xff0c;非实习&#xff09;&#xff0c;主要还是java工作&#xff0c;我现在的程度是&#xff1a;j…

探索智慧职校教职工管理的教师信息功能

在智慧职校的教职工管理体系中&#xff0c;教师信息管理犹如教师职业生涯的数字罗盘&#xff0c;引领着教师个人成长与学校教学质量的双轨并进。这一模块的核心精髓在于对教师基本信息的精细捕捉与维护&#xff0c;确保每位教师的个人资料&#xff0c;诸如姓名、性别、出生日期…

RK3588核心板怎么选?为项目挑选合适核心板的五大建议

在信息爆炸的互联网海洋中&#xff0c;面对琳琅满目的RK3588核心板产品&#xff0c;您是否也曾感到眼花缭乱&#xff0c;难以抉择&#xff1f;究竟哪一款能够完美契合您的智能设备开发项目&#xff0c;让您在最短时间内找到最合适的伙伴&#xff0c;减少研发试错&#xff0c;加…

python 打包工具 nuitka 使用笔记

个人感受: 感觉和 pyinstaller 差不多。 目前还没感受到什么差别。 但是有很多人都推荐这个。 当前只是初步尝试&#xff0c;记录一下大体过程。后面有时间了&#xff0c;再找几个例子看看。 比如找点复杂的项目&#xff0c; 或是游戏项目&#xff0c;然后打包一下看看效果。 …

Day58:并查集 108.冗余连接 109.冗余连接II

108. 冗余连接 时间限制&#xff1a;1.000S 空间限制&#xff1a;256MB 题目描述 树可以看成是一个图&#xff08;拥有 n 个节点和 n - 1 条边的连通无环无向图&#xff09;。 现给定一个拥有 n 个节点&#xff08;节点标号是从 1 到 n&#xff09;和 n 条边的连通无向图&…