一篇文章带你彻底搞懂Kotlin的协程
协程是什么本质上,协程是轻量级的线程。
协程关键名词
val job = GlobalScope.launch {
delay(1000)
println(“World World!”)
}
[*] CoroutineScope(作用范围)
控制协程代码块实行的线程,生命周期等,包罗GlobeScope、lifecycleScope、viewModelScope以及其他自界说的CoroutineScope
GlobeScope:全局范围,不会自动竣事实行
lifecycleScope:生命周期范围,用于activity等有生命周期的组件,在DESTROYED的时候会自动竣事,需额外引入
viewModelScope:viewModel范围,用于ViewModel中,在ViewModel被回收时会自动竣事,需额外引入
[*] Job(作业)
协程的计量单位,相当于一次工作任务,launch方法默认返回一个新的Job
[*] suspend(挂起)
作用于方法上,代表该方法是耗时任务,例如上面的delay方法
public suspend fun delay(timeMillis: Long) {
…
}
协程的引入
主框架($coroutines_version替换为最新版本,如1.3.9,下同)
implementation “org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version”
lifecycleScope(可选,版本2.2.0)
implementation ‘androidx.activity:activity-ktx:$lifecycle_scope_version’
viewModelScope(可选,版本2.3.0-beta01)
implementation “androidx.lifecycle:lifecycle-viewmodel-ktx:$coroutines_viewmodel_version”
简朴使用
先举个简朴例子
lifecycleScope.launch {
delay(2000)
tvTest.text=“Test”
}
上面这个例子实现的功能是等待2秒,然后修改id为tvTest的TextView控件的text值为Test
自界说延迟返回方法
在kotlin内里,对于必要延迟才能返回结果的方法,必要用suspend标明
lifecycleScope.launch {
val text=getText()
tvTest.text = text
}
suspend fun getText():String{
delay(2000)
return “getText”
}
如果在其他线程,必要使用Continuation进行线程切换,可使用suspendCancellableCoroutine 或 suspendCoroutine包裹(前者可取消,相当于后者的扩展),成功调用it.resume(),失败调用it.resumeWithException(Exception()),抛出非常
suspend fun getTextInOtherThread() = suspendCancellableCoroutine {
thread {
Thread.sleep(2000)
it.resume(“getText”)
}
}
非常捕获
协程内里的失败都可以通过非常捕获,来统一处理特殊情况
lifecycleScope.launch {
try {
val text=getText()
tvTest.text = text
} catch (e:Exception){
e.printStackTrace()
}
}
取消功能
下面实行了两个job,第一个是原始的,第二个是在1秒后取消第一个job,这会导致tvText的文本并不会改变
val job = lifecycleScope.launch {
try {
val text=getText()
tvTest.text = text
} catch (e:Exception){
e.printStackTrace()
}
}
lifecycleScope.launch {
delay(1000)
job.cancel()
}
设置超时
这个相当于系统封装了自动取消功能,对应函数withTimeout
lifecycleScope.launch {
try {
withTimeout(1000) {
val text = getText()
tvTest.text = text
}
} catch (e:Exception){
e.printStackTrace()
}
}
带返回值的Job
与launch类似的还有一个async方法,它会返回一个Deferred对象,属于Job的扩展类,Deferred可以获取返回的结果,具体使用如下
lifecycleScope.launch {
val one= async {
delay(1000)
return@async 1
}
val two= async {
delay(2000)
return@async 2
}
Log.i(“scope test”,(one.await()+two.await()).toString())
}
高级进阶
自界说CoroutineScope
先看CoroutineScope源码
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
CoroutineScope中主要包罗一个coroutineContext对象,我们要自界说只需实现coroutineContext的get方法
class TestScope() : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = TODO(“Not yet implemented”)
}
要创建coroutineContext,得要先知道CoroutineContext是什么,我们再看CoroutineContext源码
/**
[*] Persistent context for the coroutine. It is an indexed set of instances.
[*] An indexed set is a mix between a set and a map.
[*] Every element in this set has a unique .
*/
public interface CoroutineContext {
public operator fun get(key: Key): E?
public fun fold(initial: R, operation: (R, Element) -> R): R
public operator fun plus(context: CoroutineContext): CoroutineContext =
…
public fun minusKey(key: Key<*>): CoroutineContext
public interface Key
public interface Element : CoroutineContext {
…
}
}
通过解释阐明,我们知道它本质就是一个包罗Element的集合,只是不像set和map集合一样,它自己实现了获取(get),折叠(fold,添加和替换的组合),相减(minusKey,移除),对象组合(plus,如val coroutineContext=coroutineContext1+coroutineContext2)
它的主要内容是Element,而Element的实现有
[*] Job 任务
[*] ContinuationInterceptor 拦截器
[*] AbstractCoroutineContextElement
[*] CoroutineExceptionHandler
[*] ThreadContextElement
[*] DownstreamExceptionElement
[*] …
可以看到很多地方都有实现Element,它主要目的是限制范围以及非常的处理。这里我们先相识两个重要的Element,一个是Job,一个是CoroutineDispatcher
Job
[*] Job:子Job取消,会导致父job和其他子job被取消;父job取消,所有子job被取消
[*] SupervisorJob:父job取消,所有子job被取消
CoroutineDispatcher
[*] Dispatchers.Main:主线程实行
[*] Dispatchers.IO:IO线程实行
我们模拟一个类似lifecycleScope的自界说TestScope
class TestScope() : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = SupervisorJob() +Dispatchers.Main
}
这里我们界说了一个总流程线SupervisorJob()以及具体实行环境Dispatchers.Main(Android主线程),假如我们想替换掉activity的lifecycleScope,就必要在activity中创建实例
val testScope=TestScope()
然后在activity销毁的时候取消掉所有job
override fun onDestroy() {
testScope.cancel()
super.onDestroy()
}
其他使用方式同lifecycleScope,如
testScope.launch{
val text = getText()
tvTest.text = text
}
深入明白Job
CoroutineScope中包罗一个主Job,之后调用的launch或其他方法创建的job都属于CoroutineScope的子Job,每个job都有属于自己的状态,此中包罗isActive、isCompleted、isCancelled,以及一些底子操作start()、cancel()、join(),具体的转换流程如下
https://i-blog.csdnimg.cn/blog_migrate/57536d6e14b173739f6ab908d6f50180.png
我们先从创建job开始,当调用launch的时候默认有三个参数CoroutineContext、CoroutineStart以及代码块参数。
[*] context:CoroutineContext的对象,默以为CoroutineStart.DEFAULT,会与CoroutineScope的context进行折叠
[*] start:CoroutineStart的对象,默以为CoroutineStart.DEFAULT,代表立即实行,同时还有CoroutineStart.LAZY,代表非立即实行,必须调用job的start()才会开始实行
val job2= lifecycleScope.launch(start = CoroutineStart.LAZY) {
delay(2000)
Log.i(“scope test”,“lazy”)
}
job2.start()
当使用这种模式创建时默认就是new状态,此时isActive,isCompleted,isCancelled都为false,当调用start后,转换为active状态,此中只有isActive为true,如果它的任务完成了则会进入Completing状态,此时为等待子job完成,这种状态下还是只有isActive为true,如果所有子job也完成了则会进入Completed状态,只有isCompleted为true。如果在active或Completing状态下出现取消或非常,则会进入Cancelling状态,如果必要取消父job和其他子job则会等待它们取消完成,此时只有isCancelled为true,取消完成后终极进入Cancelled状态,isCancelled和isCompleted都为true
| State | isActive | isCompleted | isCancelled |
| — | — | — | — |
| | | | |
| New | FALSE | FALSE | FALSE |
| Active | TRUE | FALSE | FALSE |
| Completing | TRUE | FALSE | FALSE |
| Cancelling | FALSE | FALSE | TRUE |
| Cancelled | FALSE | TRUE | TRUE |
| Completed | FALSE | TRUE | FALSE |
不同job交互需使用join()与cancelAndJoin()
[*] join():将当前job添加到其他协程任务内里
[*] cancelAndJoin():取消操作,只是添加进去后再取消
val job1= GlobleScope.launch(start = CoroutineStart.LAZY) {
delay(2000)
Log.i(“scope test”,“job1”)
}
lifecycleScope.launch {
job1.join()
delay(2000)
Log.i(“scope test”,“job2”)
}
深入明白suspend
suspend作为kotlin新增的方法修饰词,终极实现还是java,我们先看它们的差异性
suspend fun test1(){}
fun test2(){}
对应java代码
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学结果低效又漫长,而且极易遇到天花板技能故步自封!
因此网络整理了一份《2024年Android移动开发全套学习资料》,初志也很简朴,就是渴望能够帮助到想自学提升又不知道该从何学起的朋侪,同时减轻各人的负担。
https://i-blog.csdnimg.cn/blog_migrate/231c9fa86e698bdb6fc6fdb8fca45501.png
https://i-blog.csdnimg.cn/blog_migrate/4c912d7fe24bf67a84e0eeb6fc38a5a7.png
https://i-blog.csdnimg.cn/blog_migrate/28207046bc2502b59f4344b5efaa7a44.png
https://i-blog.csdnimg.cn/blog_migrate/da135a334c887a357ef6e798b0cf0796.png
https://i-blog.csdnimg.cn/blog_migrate/d777c283cb0827d01df515350e445896.png
既有适合小白学习的零底子资料,也有适合3年以上经验的小同伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部门目次截图出来,每个节点内里都包罗大厂面经、学习笔记、源码讲义、实战项目、讲解视频,而且会持续更新!
如果你以为这些内容对你有帮助,可以扫码获取!!(备注:Android)
https://i-blog.csdnimg.cn/blog_migrate/128d976a2eced4e08ba6055983f84c10.jpeg 最后
写到这里也竣事了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个学习思绪及方向,从事互联网开发,最主要的是要学好技能,而学习技能是一条慢长而艰苦的道路,不能靠一时豪情,也不是熬几天几夜就能学好的,必须养成平时积极学习的习惯,更加必要精确的学习方向达到有效的学习结果。
https://i-blog.csdnimg.cn/blog_migrate/dd6029fd7942920f8f762fb9e15c580f.png
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
[外链图片转存中…(img-AlWX2OeG-1711933707725)]
[外链图片转存中…(img-9z7DOJkH-1711933707726)]
[外链图片转存中…(img-TzImKRpj-1711933707726)]
[外链图片转存中…(img-qyB2v2rX-1711933707726)]
既有适合小白学习的零底子资料,也有适合3年以上经验的小同伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部门目次截图出来,每个节点内里都包罗大厂面经、学习笔记、源码讲义、实战项目、讲解视频,而且会持续更新!
如果你以为这些内容对你有帮助,可以扫码获取!!(备注:Android)
https://i-blog.csdnimg.cn/blog_migrate/128d976a2eced4e08ba6055983f84c10.jpeg 最后
写到这里也竣事了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个学习思绪及方向,从事互联网开发,最主要的是要学好技能,而学习技能是一条慢长而艰苦的道路,不能靠一时豪情,也不是熬几天几夜就能学好的,必须养成平时积极学习的习惯,更加必要精确的学习方向达到有效的学习结果。
[外链图片转存中…(img-W4m8dd4p-1711933707726)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]