笔记仅做自己学习用,方便自己复习知识。若正好可以帮助到Viewer,万分欣喜~
若博客侵权,扔物线大大不允许放上面,麻烦告知
本文是扔物线Kotlin第二期协程训练营的第一篇文章
目录
2. Kotlin 协程的 suspend 关键字有什么意义?
3. 如果不使用协程,让你自己实现一个和协程类似的框架,你认为难点在哪里?
一、Kotlin协程是什么
1. 协程是什么?
协程是一个广义的概念,在很多编程语言里都有协程的编程思想。协程是一种在程序中处理并发任务的方案,也是这种方案的一个组件。
协程和线程属于同一个层级的概念,是一种和线程不同的并发任务解决方案:一套系统(可以是操作系统,也可以是一种编程语言)可以选择不同的方案来处理并发任务,你可以使用线程,也可以使用协程。
2. Kotlin的协程是什么?
Kotlin的协程和广义的协程不是一种东西,Kotlin的协程(准确地说是Kotlin for JVM的协程)是一个线程框架。类似于Java提供的线程池Executor
二、Kotlin协程的优势
1. 流式的代码写法
考虑一种需求:通过网络加载一张图片,展示在页面上,再对图片进行处理后,再展示在界面上。
需求的流程: 1. 加载图片;2.展示原图;3.对图片进行处理;4.展示处理后的图片。
其中1、3步是IO操作,需要放在后天执行,而2、4属于UI操作,需要在主线程运行。
一般情况下我们会使用线程切换或使用回调,来实现,代码如下:
new Thread(new Runnable() {
@Override
public void run() {
getBitmapFromNet(); // 1.通过网络加载图片
runOnUiThread(new Runnable() {
@Override
public void run() {
showBitmap1(); // 2.在界面上展示原图
new Thread(new Runnable() {
@Override
public void run() {
dealWithBimap(); // 3.对原图进行处理(放缩、裁剪等)
runOnUiThread(new Runnable() {
@Override
public void run() {
showBitmap2(); // 4.在界面上展示处理后的图
}
});
}
});
}
});
}
});
如果使用callback,最少也需要使用两次回调。
再来看看协程的写法:
init {
GlobalScope.launch(Dispatchers.Main) {
getBitmapFromNet() // 1.通过网络加载图片
showBitmap1() // 2.在界面上展示原图
dealWithBimap() // 3.对原图进行处理(放缩、裁剪等)
showBitmap2() // 4.在界面上展示处理后的图
}
}
suspend fun getBitmapFromNet(String url): Bitmap = withContext(Dispatchers.IO) {
Bitmap bitmap = ...
return@withContext bitmap
}
fun showBitmap1(Bitmap bitmap){
}
suspend fun dealWithBimap(Bitmap bitmap): Bitmap = withContext(Dispatchers.IO) {
Bitmap bitmap = ...
return@withContext bitmap
}
fun showBitmap2(Bitmap bitmap){
}
看init里的代码,纳尼???IO操作的代码和UI操作的代码放在一起线性执行,这代码会把界面卡死的吧。再仔细看GlobalScope.launch(Dispatchers.Main)和withContext(Dispatchers.IO),以及函数前的suspend关键词。慢慢会发现,难道这个代码那么NB,可以把线程代码和主线程代码不用切换地一起写!!!是的,这就是Kotlin的协程,它会自动切换线程,将应该在线程中运行的代码放在线程里执行,应该在UI线程运行的代码还在UI线程运行。GlobalScope.launch(Dispatchers.Main)这里的Dispatchers.Main表示该代码块中的协程代码主要在主线程运行,当协程里运行的函数没有指定线程时,就会在主线程运行。如果在函数里加上withContext(Dispatchers.IO)和suspend关键词,就代表这个函数需要在IO线程运行。线程会自动切换。
这就是协程,流式的代码写法,佩服的五体投地...
写法总结:
a. 用launch来开启一段协程,一般需要指定Dispatchers.Main
b. 把需要在后头工作的函数,使用suspend关键词标记,并调用其他suspend函数(这里的withContext(Dispatchers.IO))来真正地切换线程
c. 按照一条线写下来,线程会自动切换
2. 协程的额外天然优势:性能
不知道你在工作中有没有遇见过这种情况:比如一个查询数据库的函数,查询的量不算大,也不算小。有时候就直接把它放在主线程执行了,在测试时发现没有卡顿主线程。但是这段代码如果在性能低下的手机上运行,就可能会造成几十毫秒的卡顿,导致丢帧。这样的情况,我们很难判断这个代码是否“耗时”,有时候一个不注意就放在了主线程运行。
但是,用协程就可以很好地解决这个问题,我们可以把所有的IO操作,数据操作代码都放在后台运行,协程可以在后台执行完任务后自动切回到主线程。保证耗时代码100%放在后台执行,就能解决这方面的性能问题。
三、suspend关键字
suspend并不是来切回线程的,实际的切换线程操作是由其他函数完成的,比如withContext。
suspend主要是起到标记和提醒的作用。标记这个代码需要在协程里执行。
四、练习题
1. Kotlin的协程是什么?它有什么优势?为什么?
它是Kotlin基于JVM的线程来实现的一个并发任务处理框架(或者方案)。
优势:用起来方便,不需要回调,用纯线程的方式就可以完成线程的切回。
所有耗时任务可以保证一定放在后台执行,从而提高软件性能。
2. Kotlin 协程的 suspend 关键字有什么意义?
语法层面:作为一个标记和提醒。通过报错来提醒调用者和编译器,这是一个耗时函数,需要放在后台执行。
编译器层面:辅助Kotlin编译器来把代码转换成JVM的字节码。
3. 如果不使用协程,让你自己实现一个和协程类似的框架,你认为难点在哪里?
在不使用回调的前提下完成线程切换;
在挂起函数执行完毕时,自动判断应该回到哪个线程。
第二篇文章讲解RxJava、Retorfit、Jetpack对协程的支持,以及协程的本质探秘
第二篇文章传送:https://blog.csdn.net/bluerheaven/article/details/106971483