官方介绍协程
协程定义
协程定义:kotlin官方基于JVM的线程实现的一个并发任务处理框架,封装的线程api
- 使用方便,不使用回调实现线程切换,使用同步方式写出异步代码
- 所有的耗时任务保证一定放在后台执行
- 挂起函数执行完毕之后,协程会把它切换到原先的线程的线程。
协程的基本用法
常规函数中一般都有:call and return,协程在此之外添加了suspend和resume.
- suspend 用于暂停执行的当前协程,并保存所有的局部变量
- resume 用于已暂停的协程中暂停出恢复
supend(挂起函数)是什么,有什么意义
suspend,对协程的挂起并没有实际作用,其实只是一个提醒,函数创建者对函数的调用者的提醒,提醒调用者我是需要耗时操作,需要用挂起的方式,在协程中使用.
- 需要注意的是挂起函数只能在挂起函数或者协程作用域中使用,为什么挂起函数需要在协程作用域中使用?因为普通函数没有suspend和resume这两个特性,所以必须要在协程的作用中使用。
意义:
-
语法层面:作为一个标记和提醒。通过报错来提醒调用者和编译器,这是一个耗时函数,需要放在后台执行。
-
编译器层面:辅助 Kotlin 编译器来把代码转换成 JVM 的字节码。
怎么自定义suspend函数?
- 什么时候定义?
需要耗时操作的时候,需要定义,例如io耗时操作(请求网络);获取数据库数据;一些等待一会需要的操作;列表排除,json解析等;
- 怎么写suspend函数
给函数前加上suspend 关键字,把内容用withContext包起来
suspend fun testSuspendfun(){
withContext(Dispatchers.IO){
}
}
协程如何确保主线程安全
- Dispatchers.Main 调用程序在Android的主线程中
- Dispatchers.IO 适合主线程之外的执行磁盘或者网络io操作,例如文件的读取与写入,任何的网络请求
- Dispatcher.Default 适合主线程之外的,cpu的操作,例如json数据的解析,以及列表的排序,
协程的挂起本质
- 本质就是切线程,完成之后只不过可以自动切回来
协程挂起就是切个线程,在挂起函数执行完毕之后,协程会自动的重新切回它原先的线程,也就是稍后会被切回来的线程切换。切回来就是resume,恢复功能是协程,所以suspend函数需要在另一个suspend函数或者协程中调用.
- 什么是协程的「非阻塞式挂起」
阻塞的方式写出了非阻塞的方式
协程的创建以及取消
//创建一个协程
Val scope = CoroutineScope(Dispatchers.Main+Job())
通过Job获取协程的生命周期
scope.launch{
}
其他耗时请求,例如从数据库中获取数据
scope.async {
}
在KTX库为某些生命周期提供自己的CoroutineScope,例如ViewModel中viewModelScope,Lifecycle有lifecycleScope
协程的启动
- launch 启动新协程而不将结果返回给调用方
//创建之后,不管后续
launch(){
}
- async 启动一个新协程,并通过deferred的await方法暂停函数
//返回deferred 对象
val deferred async{
}
deferred.await()
协程的结构化并发,取消协程
协程的结构化并发,可以让协程非常便于管理。例如在关闭activity中要取消协程。如果是在线程中,取消所有的线程比较复杂。
- 取消父协程以及父里面的子协程
val scope = CoroutineScope(Dispatchers.Main+ Job())
scope.launch {
val job = launch {
val job1 = launch {
}
}
job.cancel()
}
scope.cancel()
- 取消子协程某一个
每一个协程都会返回一个job对象,通过调用job的cancle,可以去取消单个的协程的。
val scope = CoroutineScope(Dispatchers.Main+ Job())
scope.launch {
val job = launch {
val job1 = launch {
}
}
job.cancel()
}
scope.cancel()
协程中异常处理
- 在协程内部中捕获异常
val scope = CoroutineScope(Dispatchers.Main+ Job())
scope.launch {
try {
}catch (e:Exception){
}
}
网友评论