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) {


        }
    }
相关推荐
焰火1999几秒前
[Java]自定义重试工具类
java
冬奇Lab2 分钟前
稳定性性能系列之十二——Android渲染性能深度优化:SurfaceFlinger与GPU
android·性能优化·debug
SuperherRo1 小时前
JAVA攻防-Shiro专题&断点调试&有key利用链&URL&CC&CB&原生反序列化&加密逻辑
java·shiro·反序列化·有key·利用链·原生反序列化·加密逻辑
桦说编程1 小时前
简单方法实现子任务耗时统计
java·后端·监控
冬奇Lab1 小时前
稳定性性能系列之十一——Android内存优化与OOM问题深度解决
android·性能优化
爱笑的眼睛111 小时前
超越可视化:降维算法组件的深度解析与工程实践
java·人工智能·python·ai
盖世英雄酱581361 小时前
物品超领取损失1万事故复盘(一)
java·后端
CryptoRzz2 小时前
印度尼西亚(IDX)股票数据对接开发
java·后端·websocket·web3·区块链
你怎么知道我是队长2 小时前
C语言---文件读写
java·c语言·开发语言