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

【Android】浅谈kotlin协程应用

一,概述

根据【Android】kotlin协程实现原理-CSDN博客,笔者知道了kotlin#协程本质,无外乎就是挂起-恢复状态机管理。与线程不同的是挂起点由用户决定,也就是kotlin#suspend关键字,因此协程又被称作用户态线程。

本文根据协程实现原理,详细讲解下kotlin的协程如何应用。

二,应用

1,协程启动

根据是否需要协程体返回值,kotlin提供了两种创建协程的方式,launch和async

a,launch

如果不关心返回值,通过launch即可开启一个协程,launch函数返回一个Job对象,地位等同于线程的Thread对象。

GlobalScope.launch {println("Hello World!")}

launch函数需传递三个参数,如下:

context参数指协程上下文,这里可通过Dispatchers指定几个context,

Dispatchers.Default:默认上下文,内部会使用默认线程池调度挂起-恢复点。

Dispatchers.Main:UI平台相关,比如Android平台的主线程。决定挂起-恢复点在主线程。

默认是一个EmptyCoroutineContext

--------------------------------------------------------------------------------------------

start参数决定协程体执行时机,策略在CoroutineStart中,策略如下

DEFAULT --立即执行协程体

LAZY -- 被调用时才执行协程体

ATOMIC --原子地执行协程体

UNDISPATCHED --立即执行协程体直到遇到第一个挂起点。

--------------------------------------------------------------------------------------------

block参数就是传入的协程体了,定义如下,协程体本身是CoroutineScope的扩展函数。

block: suspend CoroutineScope.() -> Unit

通过launch返回一个Job实例,标准实现是StandaloneCoroutine。

Job地位在协程等同线程的Thread,提供了几个类似Thread方法:

Job#start == Thread#start

Job#cancel == Thread#interrupt

Job#isCancelled== Thread#isInterrupt

Job#join  == Thread#join

b,async

如果需要协程体返回值,通过async启动一个协程,如下

val result = GlobalScope.async {delay(100)return@async "Async返回值"}.await()println(result)

async方法返回一个Deferred对象,Deferred继承Job,通过async启动方式返回,额外新增的await挂起方法,用于获得协程体返回值。

2,协程Join

join方法定义在Job#join,也是一个挂起函数,需要在协程体内调用,

runBlocking {val job1 = GlobalScope.launch {delay(2000)println("job1 done")}job1.join()println("job2 done")}

输出如下:

job1 done
job2 done

3,协程取消

直接通过Job#cancel即可,

        val job1 = GlobalScope.launch {delay(2000)println("job1 done")}job1.cancel()println("job2 done")

输出如下:

job2 done

4,协程上下文切换

withContext可指定当前协程体上下文获得结果。

GlobalScope.launch(Dispatchers.Main) {val s = withContext(Dispatchers.IO){delay(200)println("withContext ${Thread.currentThread().name}")return@withContext "result"}println("launch ${Thread.currentThread().name}")println(s)}

withContext是一个挂起函数,即一个挂起点,通过上述写法即可实现异步编程效果,不会阻塞主线程。

5,协程超时

withTimeout可指定协程体超时时间,是一个挂起点,如果超时,下一个恢复状态不会执行,也就不会执行withTimeout后面的逻辑了

GlobalScope.launch(Dispatchers.Default) {println("launch1 ${Thread.currentThread().name}")val s = withTimeout(100){delay(200)println("withTimeout ${Thread.currentThread().name}")return@withTimeout "result"}println("launch2 ${Thread.currentThread().name}")println(s)}

输出如下:

launch1 DefaultDispatcher-worker-1

6,协程完成监听

通过Job#invokeOnCompletion即可添加协程体完成监听

GlobalScope.launch(Dispatchers.Default) {val job1 = GlobalScope.launch {delay(2000)println("job1 done")}.apply {invokeOnCompletion { c ->println("job1 completed")}}println("job2 done")}

输出如下:

job2 done
job1 done
job1 completed

7,协程添加取消监听

通过suspendCancellableCoroutine构造一个cancel监听,该回调会传递一个CancellableContinuation协程,可以调用invokeOnCancellation方法设置一个cancel监听,当该协程cancel后会立即回调监听。

suspend fun requestData():String{return suspendCancellableCoroutine { cancellableContinuation->cancellableContinuation.invokeOnCancellation {println("accept cancel")}Thread.sleep(200)cancellableContinuation.resume("requestData")}
}fun main() {val launch = GlobalScope.launch(Dispatchers.Default) {println(requestData())}Thread.sleep(100)println("invoke cancel")launch.cancel()Thread.sleep(5000)
}

输出如下

invoke cancel
accept cancel

8,协程异常处理器

启动协程时,指定异常拦截器,会拦截根协程体中的异常,如下

fun main() {GlobalScope.launch(Dispatchers.Default + CoroutineExceptionHandler { context, throwable ->println("CoroutineExceptionHandler got $throwable")}) {throw NullPointerException("null")}Thread.sleep(5000)
}

9,协程挂起点手动恢复

如果想手动恢复挂起点,可通过suspendCoroutine或suspendCancellableCoroutine两个函数实现,如下


suspend fun requestData(): String {return suspendCoroutine { cnt ->Thread {println("异步开始 Thread: ${Thread.currentThread().name}")//异步开始Thread.sleep(200)cnt.resumeWith(Result.success("Done"))}.start()}
}fun main() {GlobalScope.launch {println("Thread: ${Thread.currentThread().name}")val s = requestData()println("accept $s Thread: ${Thread.currentThread().name}")}Thread.sleep(5000)
}

当requestData执行完毕后,即可通过suspend*方法提供的Continuation手动触发resume相关方法,即可实现手动恢复挂起点。

http://www.dtcms.com/a/427319.html

相关文章:

  • 比价网站源码整站程序梦幻西游网页版app
  • dz做网站虚拟主机可以干什么
  • Windows10,11自带的Hyper-V虚拟机开启及使用方法
  • QCustomPlot 系列总结:从入门到精通的完整指南与资源整理
  • RK3566鸿蒙开发板规格书Purple Pi OH
  • 大模型落地深水区:企业 AI 转型的实践路径与价值突破
  • 金顺广州外贸网站建设图片模板网站
  • LinuxC++——etcd-cpp-api精简源代码函数参数查询参考
  • [特殊字符]️ Spring Cloud Eureka 三步通:搭建注册中心 + 服务注册 + 服务发现,通俗易懂!
  • 打工人日报#20250930
  • 六安网站建设网络服务中国都在那个网站上做外贸
  • 软件工程实践团队作业——团队组建与实践选题
  • YDWE编辑器系列教程二:物体编辑器
  • 软考-系统架构设计师 NoSQL数据库详细讲解
  • 钢铁厂设备健康监测系统:AIoT技术驱动的智慧运维革命​
  • Elasticsearch集群监控信息(亲测)
  • TARA (威胁分析与风险评估) 学习笔记
  • 网站集成微信登陆如何选择大良网站建设
  • 鸿蒙:使用Image组件展示相册图片或rawfile图片
  • ubuntu系统当前的时间和时区
  • 图解式部署:WSL2 中 Dify 本地化安装与访问故障排查指南
  • ABAP+新值过长,仅可以传输255个元素
  • 顺序队列与环形队列的基本概述及应用
  • 数组的三角和
  • 文创产品设计的目的和意义岳阳优化营商环境
  • Spring Boot 内置日志框架 Logback - 以及 lombok 介绍
  • 网站优化塔山双喜百度关键词快速排名方法
  • 第十二届全国社会媒体处理大会笔记
  • FFmpeg暂停、逐帧和音量
  • QT中的QTimer.singleShot()函数