文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

五分钟技术趣谈 | 试论Android异步框架Kotlin协程

2024-11-30 09:35

关注

Part 01

 什么是协程 

作为开发人员尤其是客户端应用开发,我们一直面临着需要解决的问题——如何防止我们的应用程序被阻塞。考虑下面一个异步应用场景。客户端顺序进行3次网络请求,最后更新UI展示结果。

图片

图1 异步场景

有多种方法实现上述需求,主流的包括:

1.1 回调方式

图2 回调代码示例

异步回调的方式虽然实现了需求,但是这种结构的代码无论是阅读还是维护起来都是极其糟糕的。这种回调函数的层层嵌套耦合,亲切地称为 "回调地狱"。

1.2 Rx方式

图3 Rx代码示例

Rx系列的链式调用,是在协程之前推荐的做法,RxJava丰富的操作符、简便的线程调度、异常处理使得大多数人满意。但是还有没有更简洁易读的写法呢?

1.3 协程方式

图4 协程代码示例

使用协程后的代码非常简洁,以顺序的方式编写异步代码,不会阻塞当前UI线程,错误处理、线程切换也和平常代码一样简单。

协程具有以下几个特点:

总而言之:协程可以简化异步编程,可以顺序地表达程序。协程使用挂起,这意味可以在代码的特定点暂停和恢复执行,无需阻塞主线程或显示创建额外的线程。

Part 02

协程的使用 

- 引入gradle依赖

图5 gradle依赖引入

- 启动协程

图6 启动协程

上面就是启动协程的代码,启动协程的代码可以分为三部分:GlobalScope、launch、Dispatchers,它们分别对应:协程的作用域、构建器和调度器。

2.1 协程作用域

指的是协程内的代码运行的时间周期范围,如果超出了指定的协程范围,协程会被取消执行。

官方库给我们提供了一些作用域可以直接来使用:

顶层函数,但是它会阻塞当前线程,主要用于测试。

全局协程作用域,它启动的协程的生命周期只受整个应用程序的生命周期的限制,且不能取消,运行时会消耗一些内存资源,这可能会导致内存泄露,不适用于业务开发。

创建一个独立的协程作用域,直到所有启动的协程都完成后才结束自身。它是一个挂起函数,需要运行在协程内或挂起函数内,为并行分解工作而设计的。

与coroutineScope类似,不同的是子协程的异常不会影响父协程,也不会影响其他子协程。

为UI组件创建主作用域。一个顶层函数,上下文是SupervisorJob() + Dispatchers.Main,说明它是一个在主线程执行的协程作用域。推荐使用。

Android官方对协程的支持是非常友好的,KTX为Jetpack的Lifecycle相关组件提供了已经绑定UV声明周期的作用域供我们直接使用:

与Lifecycle绑定生命周期,生命周期被销毁时,此作用域将被取消不会造成协程泄漏,推荐使用。

与lifecycleScope类似,与ViewModel绑定生命周期,当ViewModel被清除时,这个作用域将被取消,推荐使用。

2.2 调度器

调度器的作用是将协程限制在特定的线程执行。主要的调度器类型有:

2.3 构建器

kotlinx.continues库提供的三个基本协程构建器:

launch{}是最常用的协程构建器,不阻塞当前线程,在后台创建一个新协程,也可以指定协程调度器。

async创建一个新的协程,不会阻塞当前线程,必须在协程作用域中才可以调用,并返回Deffer对象。可通过调用Deffer.await()方法等待该子协程执行完成并获取结果。常用于并发执行-同步等待和获取返回值的情况。

runBlocking是创建一个新的协程同时阻塞当前线程,直到协程结束,主要是为测试设计。

Part 03

协程挂起、恢复原理剖析 

协程的概念最核心的点就是挂起,即函数或者某段程序可以在某个时刻暂停执行并稍后恢复。suspend是Kotlin协程最核心的关键字,使用suspend关键字修饰的函数叫作挂起函数,挂起函数只能在协程体内或者在其他挂起函数内调用。内部实现使用了Kotlin编译器的一些编译技术,被关键字suspend修饰的方法在编译阶段,编译器会修改方法的签名. 包括返回值,修饰符,入参,方法体实现。我们以下面一个简单的挂起方法来剖析。

图7 挂起函数

通过AS的工具栏中 Tools->Kotlin->show Kotlin ByteCode,得到java字节码,再点击Decompile按钮反编译成java源码:

图8 挂起函数反编译java源码

上面主要步骤为:

1️⃣函数返回值变成Object,函数入参编译后增加了Continuation参数。

2️⃣创建一个ContinuationImpl ,复写invokeSuspend()方法,在这个方法里面它又调用了一次自己,并且把continuation传递进去。

3️⃣在switch状态机中,label初始值为0,第一次会进入case 0分支,delay()是一个挂起函数,传入上面的continuation参数,会有一个Object类型的返回值。

4️⃣DelayKt.delay(2000, continuation)的返回结果如果是 COROUTINE_SUSPENDED,则直接return,那么方法执行就被结束了,方法就被挂起了。

这就是挂起的真正原理。协程的挂起本质上是方法的挂起,而方法的挂起本质上是return,协程的恢复本质上方法的恢复,而恢复的本质是callback回调。

Part 04

 总结 

异步编程是现代软件开发的重要组成部分,它允许我们创建响应迅速、可扩展的应用程序。Kotlin协程是一款轻量级、高效、易于使用的并发框架,借助Kotlin的语言优势,用同步的方式写出异步的代码,变得更加可维护和可读,有助于改善开发体验。在Android客户端开发中,结合Jetpack可以更加轻松使用不阻塞UI线程同时避免内存泄露。

来源:移动Labs内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯