“吹Kotlin协程的,可能吹错了,阿里资深Android开发带你搞懂Framework

fun execute() {
GlobalScope.launch(Dispatchers.Main) {
//切到子线程执行任务
var result = withContext(Dispatchers.IO) {
ApiService.execute(“/test”)
}
//任务执行完后自动回到主线程
tv_content.text = result
}
}

看到这里,有的人可能觉得有点怪怪的,这看起来完全不足以吸引我使用协程,用回调不好吗?

kotlin毕竟是一门比较新的语言,所以在协程中,它同时给我们提供了一些非常实用的函数,所以上面的代码可以写成下面这样:

fun execute() {
GlobalScope.launch(Dispatchers.Main) {
//切到子线程执行任务
var result = withContext(Dispatchers.IO) {
ApiService.execute(“/test”)
}
//任务执行完后自动回到主线程
tv_content.text = result
}
}

这个withContext函数的意义呢,就是能把耗时任务切到子线程去,然后任务执行完之后,又会自动切回主线程。

我们还可以继续优化一下代码,把数据请求和处理抽取到一个方法中,方便调用。

有人可能看到这里多了一个suspend关键字,这个其实就是告诉编译器这里要执行一个异步代码,调用者需要把我切到协程里,用什么切?

就是这个GlobalScope.launch(Dispatchers.Main) 。

不要想太多,就是一个编译检查而已,如果你不使用 GlobalScope.launch来调用suspend修饰的方法就不能编译通过

fun execute() {
GlobalScope.launch(Dispatchers.Main) {
val token = login()
val user = getUsrInfo(token)
tv_content.text = user.name
}
}

到了这里,我相信很多喜欢回调的朋友们心中依然觉得,这依然不足以让我来使用协程。

我们继续往下看。

利用接口回调处理有上下文关联的任务

这时候有一个需求,我们需要先获取用户的token,再通过token查询用户名称

fun execute() {
GlobalScope.launch(Dispatchers.Main) {
val token = login()
val user = getUsrInfo(token)
tv_content.text = user.name
}
}

使用协程处理有上下文关联的任务

fun execute() {
GlobalScope.launch(Dispatchers.Main) {
val token = login()
val user = getUsrInfo(token)
tv_content.text = user.name
}
}

这时候利用协程的优势就明显了很多。

但是,就是有人深深的爱着回调,而且我知道你心里想的是什么,反正用这种多层回调的场景也不多,应用程序能跑起来不影响性能就好了。

这么说确实也没错,那么我们继续往下看。

前面这种情况,getUserInfo接口是依赖于login接口返回的token的,所以不可避免的使用了回调。

但是现在有一个场景,我们需要将接口A中的接口B中的数据进行合并展示,但是这两个接口在服务端的接口设计上是没有非常强的关联的,这时候出现了两种人。

**第一种:**想了想觉得没啥办法,然后还是按照先调用接口A,成功后再调用接口B,然后在接口B的回调中进行数据合并

**第二种:**觉得第一种方式不合理,所以去找服务端“撕逼”,告诉服务端把这两个接口的数据合并到一个接口中返回,客户端处理不了就找服务端呗。这番“撕逼”下来,你有可能成功了,也有可能失败了,但最终的结果都不是非常好。

我们想象一下,假设接口A耗时100ms,接口B耗时120ms,那么实际上在并发处理的情况下,你最快只需要120ms就可以将两个数据进行合并,但是使用回调的方式需要220ms(100ms+120ms)。

之前讲的都只是代码的美观层面的东西,到这里就是性能问题了,各种小的性能问题不解决,一个app怎么可能有比较好的用户体验呢。

我们来看看通过协程可以怎么做:

fun execute() {
GlobalScope.launch(Dispatchers.Main) {
//使用async发起两个异步请求
val one = async { one() }
val two = async { two() }
//使用await进行合并
val result = one.await() + two.await()
tv_content.text = result
}
}

看到这里,我们再来看协程这个名字,英文名是Coroutine,中文全称叫做“协同程序”,结合我们前面说的内容,你是否对协程有了新的认识呢?

协程就是协同多个程序之间进行合作,帮助我们轻松的写出复杂的并发代码,甚至还能用非常简单的方式实现原本不可能实现的并发任务。这就是我们为什么要学习协程的理由。

到底什么是非阻塞式挂起

网上很多文章都提到协程的挂起是非阻塞式的,挂起是什么呢?

就是我们前面说的withContext(Dispatchers.IO)挂起函数,当然还有delay、async,说白了只要不影响我们主线程的工作,那就是被挂起了,这里的”挂起“两个字用的非常玄乎,感觉像挂在我们的主线程,其实按照我上面的分析,更贴切的说法是”切到另一个线程“。

再来分析这个非阻塞式,阻塞很简单,就是字面意思,那既然是阻塞,那总得知道阻塞了什么吧?

在我们Android中,其实就是阻塞了主线程的运行,那反过来非阻塞式其实就是没有卡住主线程的运行.

所以,协程是非阻塞式挂起的是什么意思呢?就是一段程序切到另一个线程执行,不会卡住到主线程。

没错,这听起来就像是一句废话,但是网上很多文章却用一些更高级的词汇来说出来这个废话,让大家去花更多的心思去琢磨。不用想那么多,非阻塞式挂起其实就是这么简单~

总结

本文只是给你讲了协程是什么,并用一个小例子给你展示了协程的作用,更多API使用方式还是推荐看官方文档哦.

最后做一个总结

  1. 协程(Coroutine)就是协同程序,而Kotlin协程就是一个基于Java Thread API封装的工具包,帮助我们轻松的写出复杂的并发代码
  2. kotlin协程相较于线程池,并没有什么性能上的优势
  3. 非阻塞式挂起没什么特别的,java子线程也同样是非阻塞式的
  4. 如果你熟悉Rxjava,你再对比一下协程,你会发现协程比Rxjava还好用

由于文章篇幅问题,关于kotlin的学习资料我就不一一放出来了,需要这方面资料的程序员可以**私信我【学习】**我免费分享给大家。

或者直接点击下面链接领取
Android学习PDF+架构视频+面试文档+源码笔记

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

.(img-EM1LaNdC-1710929935264)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-jMTaPHev-1710929935264)]

  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值