美文网首页
kotlin 协程基础

kotlin 协程基础

作者: Bfmall | 来源:发表于2023-08-13 11:37 被阅读0次

一、什么是协程?

协程:可以简单地将它理解成一种轻量级的线程

协程允许我们在单线程模式下模拟多线程编程的效果,
代码执行时的挂起与恢复完全是由编程语言来控制的,和操作系统无关。

这种特性使得高并发程序的运行效率得到了极大的提升。

协程让异步线程同步化,杜绝回调地狱。

协程最核心的点就是,函数或者一段程序能够被挂起,稍后再在挂起的位置恢复。

二、Android中协程用来解决什么问题?

1、处理耗时任务:这种任务常常会阻塞主线程
2、保证主线程安全:即确保安全地从主线程调用任何suspend函数

三、需要添加地依赖

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"

四、创建协程

1、runBlocking:阻塞主线程

    runBlocking {

    }

2、GlobalScope.launch:顶级协程,不阻塞主线程

    GlobalScope.launch {
        
    }

3、在协程中使用 launch 新建多个子协程(同一线程池),launch 和 launch之间是并发执行,
只有在 CoroutineScope 作用域下才可以使用 launch。

    GlobalScope.launch {
        launch {

        }
        launch {

        }
        launch {

        }
    }

    runBlocking {
        launch {

        }
        launch {

        }
        launch {

        }
    }

    CoroutineScope(Dispatchers.Default).launch {
        
    }

五、协程的两部分

Kotlin的协程实现分为两个层次:

* 基础设施层,标准库的协程API,主要对协程提供了概念和语义上的最基本的支持
* 业务框架层,协程的上层框架支持

我们可以使用基础设施层创建协程:

val continuation = suspend { // 协程体
    5
}.createCoroutine(object : Continuation<Int> {
    override val context: CoroutineContext = EmptyCoroutineContext
    override fun resumeWith(result: Result<Int>) {
        println(result)
    }
})
continuation.resume(Unit)

我们知道了其实创建协程的过程,在基础设施层中也是看起来那么复杂。

六、协程的挂起与恢复

常规函数基本操作包括:invoke(或call)和return,协程新增了suspend和resume:
* suspend:也称为挂起或暂停,用于暂停执行当前协程,并保存所有局部变量;
* resume:用于让已暂停的协程从其暂停处继续执行。

使用suspend关键字修饰的函数叫作挂起函数。

挂起函数只能在协程体内或其他挂起函数内调用。

七、协程调度器

Dispatchers.Default:表示会使用一种默认低并发的线程策略,当你要执行的代码属于计算密集型任务时,
    开启过高的并发反而可能会影响任务的运行效率,此时就可以使用Dispatchers.Default。
场景:数组排序,JSON数据解析,处理差异判断。

Dispatchers.IO:表示会使用一种较高并发的线程策略,当你要执行的代码大多数时间是在阻塞和等待中,
    比如说执行网络请求时,为了能够支持更高的并发数量,此时就可以使用Dispatchers.IO。
场景:数据库、文件读写、网络处理

Dispatchers.Main:则表示不会开启子线程,而是在Android 主线程中执行代码,
    但是这个值只能在Android 项目中使用。
场景:调用suspend函数、调用UI函数、更新LiveData

八、挂起和阻塞

GlobalScope.launch(Dispatchers.Main) { // 主线程
    // delay是一个非阻塞式的函数,让协程挂起,不影响其它协程运行
    // 让协程挂起15秒
    delay(15000) // 假设有15s的耗时操作
}

以上协程已经切换到了Main线程调度器,
delay 是挂起函数,可以让delay函数暂时挂起,挂起函数不会阻塞线程(主线程或其它线程),
另外,协程体本身就是一个挂起函数。

如果不使用协程,在主线程中,存在15秒耗时操作,会引起ANR。

比如:Thread.sleep(15000)

Thread.sleep函数是真正的阻塞函数,它会让当前线程阻塞。


耗时处理一般在异步线程来处理,异步线程不仅创建了多余的内存,而且异步线程执行完之后,需要切换线程之后才能更新UI,
如果不使用协程,使用存java的方式切换线程,代码量较多,后期维护成本较大。

使用协程,可以简化代码,而且优化了并发速度。

我们知道,协程体中代码是暂时被挂起的,不会引起阻塞,但是为了更好的并发,我们将耗时操作放到Dispatchers.Default或者Dispatchers.IO调度器上处理,优化有的协程代码如下:

        GlobalScope.launch(Dispatchers.Main) { // 主线程
            withContext(Dispatchers.Default) { // 耗时操作在IO中执行
                // delay是一个非阻塞式的函数,让协程挂起,不影响其它协程运行
                // 让协程挂起15秒
                delay(15000) // 假设有15s的耗时操作
            }
            // 更新UI
            //。。。执行更新UI操作。。。
        }

九、协程的任务泄露

当某个协程任务丢失,会导致内存、CPU、磁盘等资源浪费,甚至发送一个无用的网络请求,这种情况称为任务泄露。

为了能够避免协程泄露,Kotlin引入了结构化并发机制。

使用结构化并发可以做到:

取消任务,当某项不再需要时取消它。
追踪任务,当任务正在执行时,追踪它。
发出错误信号,当协程失败时,发出错误信号表明有错误发生。
CoroutinesScope:定义协程必须指定其CoroutinesScope,它会跟踪所有协程,同样它还可以取消由它所启动的所有协程。
常用的相关API有:

GlobalScope,生命周期是process级别的,即使Activity或Fragment已经被销毁,协程仍然在执行。

GlobalScope.launch { }

MainScope,在Activity中使用,可以在onDestory中取消协程。

private val mainScope = MainScope()

mainScope.launch { // 创建协程

}

// 在onDestroy中取消协程,防止协程泄露
override fun onDestroy() {
    super.onDestroy()
    mainScope.cancel()
}

一般使用委托的方式取处理:

定义一个基类:

  abstract class ScopedActivity: AppCompatActivity(), CoroutineScope by MainScope(){
      override fun onDestroy() {
          super.onDestroy()
          cancel()
      }
  }

这样就可以方便的在Activity中使用协程了,而且还不用担心协程泄露,
在Activity中使用时,直接launch就可以了:

launch {
  
}

viewModelScope,只能在ViewModel中使用,绑定ViewModel的生命周期。

继承 ViewModel 或 AndroidViewModel

依赖:
implementation"androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"

viewModelScope.launch { // 创建协程

}

lifecycleScope,只能在Activity、Fragment中使用,会绑定Activity和Fragment的生命周期。

依赖:
  implementation"androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"

  lifecycleScope.launch {
      
  }

 和生命周期绑定,会自动取消。

作者:NoBugException
链接:https://www.jianshu.com/p/d7efc3e3cc19
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关文章

网友评论

      本文标题:kotlin 协程基础

      本文链接:https://www.haomeiwen.com/subject/bubfmdtx.html