美文网首页
Kotlin协程

Kotlin协程

作者: 橙子6193 | 来源:发表于2022-03-04 20:58 被阅读0次

1、协程的概念

相当于轻量级线程,线程的切换需要操作系统进行调度,而协程在编译语言层面就能实现自由切换,开销比线程要小的多,这种特性使得高并发程序的执行效率得到了极大的提升

2、协程的优点

可控制、开销小、语法糖(减少回调,已同步的写法代替之前异步的写法)
协程与线程是属于一个层级的,但是却又和线程处理并行任务有着不同的解决方案,协程可以在处理完并发任务之后,自动切回UI(mian/主)线程;线程处理完并发任务默认是不会直接切回UI(mian/主)线程,需要我们手动去切回UI(mian/主)线程,因此,协程不仅切换成本小,还可以避免回调地狱

3、协程的用法

首先引入依赖

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

GlobalScope.launch

class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        GlobalScope.launch {
            delay(1500)
            println("codes run in coroutine scope")
        }
        sleep(1000)
    }
}

GlobalScope.launch创建的协程是顶层协程,返回值时Job,会随着线程的销毁而销毁,因此需要sleep 1s,delay只能用于协程作用域或挂起函数里,delay在协程中调用时只会阻塞当前协程,不会影响其它协程

runBlocking

class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        runBlocking {
            launch {
                delay(1000)
                println("codes run in runblocking")
            }
        }
    }
}

runBlocking 可以阻塞当前线程直到其中的所有协程全部执行完成,一般在测试环境使用

挂起函数和coroutineScope

当协程内代码过多时,我们可以把其中一部分代码抽出来写成一个方法,但如果需要在方法中使用delay方法时,需要把这个方法声明成挂起函数,用suspend修饰,不过现在还是不能使用launch,因为挂起函数不是协程作用域,如果想在挂起函数中使用launch方法,可以用coroutineScope函数使挂起函数拥有协程作用域,如下:

//挂起函数中使用delay方法
suspend fun method1(){
        delay(1000)
        println("test  fdfda")
    }
//使用coroutineScope声明一个带协程作用域的方法
suspend fun method2()= coroutineScope{
        launch {
            println("method2")
        }
    }

coroutineScope会阻塞当前协程,直到它内部的所有协程都执行完
在实际项目中,由于runBlocking可能会阻塞当前线程,一般不用,而Global.launch这种顶层协程每个会返回一个Job,管理起来比较麻烦,所以一般也不使用,下面介绍一种项目中常用的协程使用

        val job=Job()
        val scope= CoroutineScope(job)
        scope.launch {
            println("111111")
            delay(100)
            println("111111")
        }
        scope.launch {
            println("22222")
            delay(100)
            println("22222")
        }
        //job.cancel()
        sleep(1000)

使用Job可统一取消所有通过CoroutineScope启动的协程(这种和顶层协程一样,不会阻塞线程,随线程销毁而结束),因为launch函数只能返回job对象,那么如果我们需要获取一个协程的返回结果时,就得使用async函数了

能获取协程结果的async函数

async必须在协程作用域才能调用,它会创建一个新的协程并返回一个Deferred对象,调用Deferred对象的await方法即可获取协程的结果,如下:

//能获取协程结果的async函数
        runBlocking {
            val result=async {
                5+6
            }.await()
            println(result)
        }
//await会阻塞当前协程(不影响其它协程),直到可以获取到async的结果
        runBlocking {
            val result=async {
                sleep(1000)
                println("第一个async函数")
                5+6
            }.await()
            async {
                println("第二个async函数")
            }.await()
            println(result)
        }
//async函数同时执行
        runBlocking {
            val start=System.currentTimeMillis()
            val deferred1=async {
                delay(1000)
                println("第一个async函数")
            }
            val deferred2=async {
                delay(1000)
                println("第二个async函数")
            }
            deferred1.await()
            deferred2.await()
            println(System.currentTimeMillis()-start)

强制要求指定线程参数的协程

       //强制要求指定线程的协程
        runBlocking {
            withContext(Dispatchers.Default){
                delay(1000)
                println("withContext"+Thread.currentThread().id)
            }
        }
        println("主线程id=${Thread.currentThread().id}")

共有三种类型,分别是Dispatchers.Default(适用于低并发)、Dispatchers.IO(适用于高并发)、Dispatchers.Main(不会开启子线程,会在主线程执行)

协程简化回调

    //常见的网络请求回调
    HttpUtil.sendHttpRequest(url,object:HttpCallbackListener{
        override fun onFinish(response:String){
            //得到服务器返回的具体内容
        }
        override fun onError(e:Exception){
            //异常情况处理
        }
    })
    //使用协程简化回调
    suspend fun request(url:String):String{
        return suspendCoroutine { continuation ->
            HttpUtil.sendHttpRequest(url,object:HttpCallbackListener{
                override fun onFinish(response:String){
                    //得到服务器返回的具体内容
                    continuation.resume(response)
                }
                override fun onError(e:Exception){
                    //异常情况处理
                    continuation.resumeWithException(e)
                }
            })
        }
    }
    //后续网络请求可直接这么写
    try{
        val response=request("xxxx")
        //对服务器响应的数据进行处理
    }catch(e:Exception){
        //对异常情况进行处理
    }

4、协程的原理

相关文章

网友评论

      本文标题:Kotlin协程

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