Kotlin协程

什么是协程

由Kotlin官方对多线程操作提供的一系列API

类似于Java的Thread Android AsyncTask

借助Kotlin语言看起来写同步的代码写异步处理操作。也就是非阻塞式挂起

协程的功能

  1. 协程最基本的功能是并发操作,多线程。可以切换任务到后台和前台。
1
2
3
4
5
6
launch(Dispatchers.IO){
saveToDatabase(data)
}
launch(Dispatchers.Main){
updateViews(data)
}
  1. 可以把不同线程的代码写在同一个代码块
1
2
3
4
launch(Dispatchers.Main){//开始:主线程
val user = api.getUser()//网络请求:后台程序
nameTv.text = user.name//更新UI:主线程
}

如果对于Java来说:想要这样做,是不可能的,那么你只能不停地回调,才能完成这样的操作。

  1. 开发难度降低(合并协程)

对于一个需求来说,如果需要并行执行两个请求,但是由于自己不会处理数据合并,请求的合并,把这两个请求变成了串行,那么网络请求时间就多了一倍

如果用协程

1
2
3
4
5
6
launch(Dispatchers.Main){
val avatear = async{api.getAvater(user)}//获取用户头像
val logo = async{api.getCompanyLogo(user)}//获取公司logo
val merged = suspendingMerge(avatear,logo)//合并数据请求
show(merged)
}

协程怎么用

当你拥有一个生成协程函数launch(),通过指定线程来完成请求操作。

1
2
3
launch(Dispatchers.Io){
val image = getImage(imageId)
}

如果你要切回主线程更新UI怎么做?

1
avatarImageView.setImageBitmap(image)

当然不能像前面一样做,因为只是一个伪代码

所以对于其想要切换回来来说

1
2
3
4
5
6
launch(Dispatchers.Main){
val image = withContext(Dispatchers.Io){
getImage(imageId)//语法糖得到IO线程数据
}
avatarIv.setImageBitmap(image)//在主线程中进行展示UI
}

对于上面的withContext来说:这是一个函数,我们借助这个函数就可以去切换到Io线程得到数据。

那么总结一下:协程的定义:协作式的例程

如何写

1
2
3
4
5
6
7
8
9
launch(Dipatchers.Main){
withContext(Dispatchers.IO){
···
}
withContext(Dispatchers.IO){
···
}
···
}

这就是协程。

可是我想写的更加优美一下,如何美化这个代码呢?

这里先介绍一个函数:suspend函数

当代码执行到suspend函数的时候,代码会挂起,而且这个挂起是非阻塞式的,不会阻挡线程

什么是挂起?

用一个词来解释挂起:脱离 这个词是十分的恰当。

也就是说,当一个Launch函数执行到了suspend函数的时候,这个协程从正在执行的线程脱离了,也就是线程在这个代码开始不执行协程了,注意不是停止。

那么对于这个线程有可能是IO线程也有可能是主线程,那么对于其来说,自己做自己的事情去了

那剩下的挂起的代码怎么办?

1
2
3
4
5
6
7
8
9
launch(Dispatchers.Main){
val image = suspendingGetImage(imageId) //剩下两行代码转到IO线程执行。挂起以后去了IO线程执行。结束了就把线程切回来。完成了一次封装执行
avatarIv.setImageBitmap(image)
}
suspend fun suspendingGetImage(imageId:String){
withContext(Dispatchers.IO){
getImage(imageID)
}
}

所以为什么用Dispatcher关键字:调度器,而不是Thread线程这个关键字的原因所在。

因为他需要去调度线程。切换回来线程

所以什么是挂起:暂时离开,执行结束后切回来。也就是切线程 这个行为就叫resume恢复

什么是suspend函数?

所以这个函数就是挂起函数,而且这就是为什么不阻塞的原因。

但是还有个问题,我们在suspend函数里面其实是withContext函数来实现的切换,而且我们也可以自定义来进行线程的切换

但是suspend关键字到底起什么作用?

suspend的作用:提醒

也就是函数创建者对函数调用者的提醒,就是简单的一个标记罢了。它和withContext函数一起实现了标志同步!!!!

提醒调用者:这是一个耗时函数,所以你用的时候要小心。仅此而已罢了。

可是又有人说:我不想告诉调用者这是个耗时操作为什么会报错?

因为标记同步机制,你withContext函数返回值是suspend,所以就要申明这个suspend