Android开发(Kotlin) 协程

目录

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

kotlin 复制代码
fun foo(){
	a()
	b()
	c()
}

fun bar(){
	x()
	y()
	z()
}

在协程A中去调用foo()方法,协程B中去调用bar()方法,他们会运行在同一个线程当中,在执行foo()方法时都有可能被挂起转而执行bar()方法,执行bar()方法时也随时都有可能被挂起转而执行foo()方法。

协程允许我们在单线程下模拟多线程编程的效果。

协程的基本用法

启动一个协程

kotlin 复制代码
fun main() {

    GlobalScope.launch {

        println("codes run in coroutine scope")
       
    }
}

运行后发现没有打印出来,原因是还没等打印出来,程序就结束了。

kotlin 复制代码
fun main() {

    GlobalScope.launch {

        println("codes run in coroutine scope")
    }
    Thread.sleep(1000)
}

执行结果

kotlin 复制代码
codes run in coroutine scope

Process finished with exit code 0

如果程序结束,协程没执行完也会结束。可以使用runBlocking,在协程中所有代码都运行完了之后再结束。

kotlin 复制代码
fun main() {
    runBlocking {
        println("codes run in coroutine scope")
        delay(1500)
        println("end")
    }
}
kotlin 复制代码
codes run in coroutine scope
end

Process finished with exit code 0

创建多个协程

kotlin 复制代码
    runBlocking {
        
        launch {

            println("codes run in coroutine scope")
            delay(1500)
            println("end")
        }

        launch {

            println("111111111111111")
            delay(1500)
            println("end2")
        }
    }

代码中launch 必须在协程中才能调用,它会在当前协程的作用域下创建子协程。子协程的特点是如果外层作用域的协程结束了,该作用域下的所有子协程也会一同结束。

逻辑越来越复杂,可以将部分代码抽离到一个函数中。如何在抽离出的函数中使用像delay()这种挂起函数,可以使用suspend关键字,可以将任意函数声明成挂起函数。

kotlin 复制代码
suspend fun  myCall(){

    println("hi ")
    delay(1000)
}

suspend 无法提供协程作用域,不能调用launch函数。使用coroutineScope函数可以处理此问题。coroutineScope是一个挂起函数。

kotlin 复制代码
suspend fun  myCall(){

    coroutineScope {

        launch {
            println("hi ")
            delay(1000)
        }
    }
}

coroutineScope会将外部协程挂起,只有当它作用域内的所有代码和子协程都执行完毕后,coroutineScope函数之后的代码才能得到运行。

coroutineScope函数只会阻塞当前协程,不会造成性能上的问题。runBlocking 会挂起外部线程,如果在主线程中当中调用它的话,可能会导致界面卡死,一般不推荐使用。

作用域构建器

取消协程

kotlin 复制代码
    val job  = GlobalScope.launch { 
        
    }
    job.cancel()

比较常用的写法

kotlin 复制代码
    val job  = Job()
    val scope = CoroutineScope(job)
    scope.launch { 
        
    }
    
    job.cancel()

CoroutineScope.launch 所创建的协程,都会被关联在job对象的作用域下面,调用一次cancel方法,可以将同一作用域的所有协程全部取消。

有执行结果的协程,要使用async函数,会创建一个新的子协程并返回一个Deferred对象,获取执行结果需要调用Deferred对象的await()方法。

kotlin 复制代码
    runBlocking {

        val result = async {
            5 + 5
        }.await()
        println(result)
    }

await()如果代码块中的代码还没执行完,那么await()方法会将当前协程阻塞,直到获取到async 的结果。

withContext()

调用withContext()函数后,会立即执行代码块中的代码,同时将外部协程挂起,当代码块中的代码执行完成后,会将最后一行代码作为返回值返回。withContext()函数强制要求指定一个线程参数。

kotlin 复制代码
    runBlocking {

        val result = withContext(Dispatchers.Default) {
            5 + 5
        }
        println(result)
    }

Dispatchers有三种值,Dispatchers.Default、Dispatchers.Main、Dispatchers.IO,Dispatchers.Default表示会使用一种默认低并发的线程策略,Dispatchers.IO表示会使用一种较高并发的线程策略,当你要执行的代码大多数时间是在阻塞和等待中,比如说执行网络请求时。Dispatchers.Main则表示在android主线程执行。

使用协程简化回调的写法

suspendCoroutine函数必须在协程作用域或挂起函数中才能调用,主要作用是将当前协程立即挂起,在一个普通的线程中执行Lambda表达式中的代码。Lambda表达式的参数列表上会传入一个Continuation参数,调用它的resume()或resumeWithException()来让协程恢复。

简化Retrofit的网络请求

kotlin 复制代码
            val appService = ServiceCreator.create<AppService>()
            appService.getData().enqueue(object : Callback<WordListBean>{
                override fun onResponse(call: Call<WordListBean?>, response: Response<WordListBean?>) {

                    Log.d("ClickActivity",response.body().toString())
                }

                override fun onFailure(call: Call<WordListBean?>, t: Throwable) {

                    Log.d("ClickActivity",t.toString())
                }
            })

使用suspendCoroutine

kotlin 复制代码
    suspend fun <T> Call<T>.await():T{

        return suspendCoroutine { continuation ->

            enqueue(object : Callback<T>{
                override fun onResponse(call: Call<T?>, response: Response<T?>) {

                    val body = response.body()
                    if(body !=null){

                        continuation.resume(body)
                    }else{

                        continuation.resumeWithException(RuntimeException("body is null"))
                    }
                }

                override fun onFailure(call: Call<T?>, t: Throwable) {

                    continuation.resumeWithException(t)
                }

            })
        }
    }
kotlin 复制代码
    suspend fun getAppData() {

        try {

            val appList = ServiceCreator.create<AppService>().getData().await()
        } catch (e: Exception) {


        }
    }
相关推荐
benbenAItalk4 小时前
数字人口播视频的批量生产实践:素材规范、任务编排与质量验收
java·前端·音视频
sunshine22 girl4 小时前
Java学习二 基本语法2, 算术运算符
java·学习
niucloud-admin4 小时前
JAVA V6 多商户商城 开发文档——插件目录结构
java·开发语言
2601_962885724 小时前
如何用 Python 扫描 A 股跳空缺口并统计缺口回补概率?
java·前端·python
滕州市燕猫虎计算机科技工作室个体工商户4 小时前
Java锁
java·开发语言
shehuiyuelaiyuehao6 小时前
1计算机是如何工作的
java·计算机网络
一航jason7 小时前
Android平台推理框架及试用场景模型对比
android·人工智能·ai·架构·ai编程·llama
一航jason7 小时前
Android 端侧大模型推理框架对比
android·人工智能·ai·ai编程·llama·ai-native
letisgo57 小时前
JAVA 高级进阶07篇《@Transactional失效的8个场景:代理机制到传播行为》
java·面试·transactional·spring事务·aop动态代理
水域安全老周7 小时前
水趣钓鱼救生衣专利拆解:两级锁紧如何解决落水人衣分离
java·前端·网络