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


        }
    }
相关推荐
河铃旅鹿3 小时前
Android开发-java版:Framgent
android·java·笔记·学习
y***61314 小时前
【springboot】Spring 官方抛弃了 Java 8!新idea如何创建java8项目
java·spring boot·spring
tanxinji4 小时前
RabbitMQ四种交换器类型详解及示例
java·rabbitmq
刘一说4 小时前
一次生产环境 Tomcat 7 + JDK 7 应用启动失败的完整排查与修复实录
java·tomcat·firefox
邮专薛之谦5 小时前
Kotlin 全知识点复习+详细梳理
windows·kotlin·android studio·idea
七夜zippoe5 小时前
JVM类加载机制(Class Loading)详解:双亲委派模型与破坏实践
java·开发语言·jvm·类加载·双亲委派
黄昏恋慕黎明6 小时前
spring MVC了解
java·后端·spring·mvc
-Xie-7 小时前
Redis(八)——多线程与单线程
java·数据库·redis
Kuo-Teng7 小时前
LeetCode 279: Perfect Squares
java·数据结构·算法·leetcode·职场和发展