kotlin学习
协程Coroutines学习
简单小Demo:通过协程下载一张网络图片并显示出来
文章目录
前言
我们所有的代码都是跑在线程中的,而线程是跑在进程中的。 协程没有直接和操作系统关联,但它不是空中楼阁,它也是跑在线程中的,可以是单线程,也可以是多线程。 单线程中的协程总的执行时间并不会比不用协程少。 Android 系统上,如果在主线程进行网络请求,会抛出 NetworkOnMainThreadException,对于在主线程上的协程也不例外,这种场景使用协程还是要切线程的 。一、如何开启一个协程?
协程是跑在线程里的
launch {
......
}
用以上launch函数可以开启一个协程,但是launch并不是顶层函数。有以下三种方法来创建协程
// 方法一,使用 runBlocking 顶层函数
runBlocking {
getImage(imageId)
}
// 方法二,使用 GlobalScope 单例对象
// 👇 可以直接调用 launch 开启协程
GlobalScope.launch {
getImage(imageId)
}
// 方法三,自行通过 CoroutineContext 创建一个 CoroutineScope 对象
// 👇 需要一个类型为 CoroutineContext 的参数
val coroutineScope = CoroutineScope(context)
coroutineScope.launch {
getImage(imageId)
}
第一种方法不推荐,因为它是线程堵塞的
第二种方法创建的协程生命周期会和APP的一样,不适合执行后台任务
第三种较为推荐,可以通过context参数来管理和控制协程的生命周期
运用协程可以方便的进行线程的切换
//切换到IO线程
coroutineScope.launch(Dispatchers.IO) {
...
}
//切换到主线程
coroutineScope.launch(Dispatchers.Main) {
...
}
但是以下的一种场景,如果在IO线程进行了网络请求获得数据需要在主线程更行UI界面,操作需要切换回主线程。这时候就会出现嵌套操作,如何解决呢?如果只是使用launch函数,协程并不能比线程完成更多操作,但是协程提供了一个很实用的函数withContext()
这个函数可以切换到指定的线程,并且执行完后自动返回执行之前的线程
coroutineScope.launch(Dispatchers.Main) {
// 👈 在 UI 线程开始
val image = withContext(Dispatchers.IO) {
// 👈 切换到 IO 线程,并在执行完成后切回 UI 线程
getImage(imageId) // 👈 将会运行在 IO 线程
}
avatarIv.setImageBitmap