kotlin-协程基本操作
一、什么是协程?
1、协程是一个异步任务的解决方案,可以在不同的线程间来回切换,不会阻塞当前线程。
2、是一种轻量级的线程,可以挂起和恢复执行。
二、协程的特性
1、挂起和恢复:协程可以在执行过程中被挂起,稍后再恢复执行。能够高效的处理耗时的操作,比如网络请求或读写文件。
2、轻量级:协程的创建和销毁非常小,通常可以在同一线程中创建成千上万的协程,而不必担心内存和性能问题。
3、可组合性:协程可以与其他协程进行组合,方便地构建复杂的异步操作。
三:创建协程的三种方式:
1、runBlock{}
2、GlobalScope.launch{}
3、CoroutineScope(Dispatchers.IO).launch{}
四:工作原理
协程是通过suspend函数和CoroutineScope来实现的,协程的基本构建块是挂起函数,这些函数可以在协程中调用,并且可以被挂起。
五:suspend关键字
什么是挂起?不影响主线程的工作,理解为切换到一个指定的线程。
1、suspend函数是可以在协程中挂起的函数,它们的调用不会阻塞线程,而是将协程挂起,直到操作完成。
2、可以看成是一种提醒,表示这是一个耗时方法,不能直接执行,需要在协程中或者被suspend修饰的方法中调用,所以我们在写某个耗时方法的时候需要给它加上suspend关键字,可以有效避免我们在主线程中调用耗时操作造成应用卡顿的情况。
六:runBlocking、launch、async操作符
1、runBlocking :会阻塞当前线程,等待suspend返回的结果
2、launch:非阻塞,启动一个协程,不返回结果
3、async:启动一个协程并返回Deferred对象,可以通过该对象获取结果
4、delay:延迟操作
5、withContext:用来在不同的上下文(Context)中执行代码,并在代码执行完毕后返回结果,指定协程执行的线程和启动模式。会阻塞当前协程,直到指定的上下文代码执行完毕,并返回结果。
七:协程调度器
1、Dispatchers.Main:用于在主线程中执行协程,适用于UI更新
2、Dispatchers.IO:用于进行I/O操作的协程,适用于网络请求或者文件操作
3、Dispatchers.Default:用于执行CPU密集型任务的协程
八:协程的生命周期:
1、GlobalScope:是应用、进程(process)级别,Activity销毁,协程依然还执行,存在整个app生命周期。适用于执 行长期运行的异步任务,比如定时任务。
2、MainScope:跟Activity生命周期一样,Activity销毁,MainScope也被销毁。指定了Dispatchers.Main作为其默认协程
调度器
3、CoroutineScope:协程作用域,是一个接口,具体实现类:GlobalScope、MainScope
4、ContextScope:上下文作用域
5、LifecycleScope:只能在Activity、Fragment中使用,跟Activity生命周期关联,Activity销毁就不存在
6、ViewModelScope:只能在ViewModel中使用,绑定ViewModel的生命周期
九:协程的优势:
1、简化异步代码:使用协程,可以同步的方式编写异步代码,使代码更加易于理解和维护
2、减少回调地狱:传统的异步编程通常依赖于回调函数,容易导致“回调地狱”,而协程通过挂起函数解决了这个问题
3、轻量级和高效:协程的上下文切换开销非常小,可以在同一线程中高效管理多个线程
例子:
package com.example.androidkotlindemo2.testcoroutine import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext import org.junit.Test import java.time.LocalDateTime import java.time.format.DateTimeFormatter /** * Author : wn * Email : maoning20080809@163.com * Date : 2024/11/10 9:42 * Description : 测试协程 */ class TestCoroutine { @Test fun test(){ test1Suspend() //testLaunch() //testAsync() //testWithContext() } private fun test1Suspend(){ println("${getTime()} fetchData 1") runBlocking { //有返回值 var result = fetchData() println("${getTime()} fetchData 3 result : ${result}") } var job1 = CoroutineScope(Dispatchers.IO).launch { //调用没有返回值 var result = fetchData() println("${getTime()} fetchData 4 result : ${result}") "test1Suspend job1" } println("${getTime()} fetchData 5 job1 : ${job1}, ${job1.isCompleted}") val deferred = GlobalScope.async { //调用没有返回值 var result = fetchData() println("${getTime()} fetchData 6 result : ${result}") } println("${getTime()} fetchData 7 result : ${deferred.isCompleted}") println("${getTime()} fetchData 2") } /** * 非阻塞,启动一个协程,不返回结果 */ private fun testLaunch(){ CoroutineScope(Dispatchers.IO).launch { println("${getTime()} testLaunch fetchData a1 ------") var resul1 = fetchData() println("${getTime()} testLaunch fetchData a1 ------ ${resul1}") } var jon2 = CoroutineScope(Dispatchers.IO).launch { println("${getTime()} testLaunch fetchData a2 ------") var resul2 = fetchData() println("${getTime()} testLaunch fetchData a2 ------ ${resul2}") "testLaunch2 result2 = ${resul2}" } println("${getTime()} testLaunch fetchData a2 jon2 ------ ${jon2}") //runBlocking会阻塞当前主线程,也就是Dispatchers.Main会等待runBlocking执行完成后,才去执行。这是AndroidJUnitRunner测试代码,真实环境,把前面2个Dispatchers.IO替换为Dispatchers.Main能看出效果 runBlocking { //想要获取fetchData()返回的值往外传递,必须使用runBlocking、Dispatchers.IO、await() var job3 = CoroutineScope(Dispatchers.IO).async { println("${getTime()} testLaunch fetchData a3 ------") var resul3 = fetchData() println("${getTime()} testLaunch fetchData a3 ------ ${resul3}") "testLaunch2 result3 = ${resul3}" } var job3Result = job3.await() println("${getTime()} testLaunch fetchData a3 job3 ------ ${job3Result}") } } /** * 测试Async:启动一个协程并返回Deferred对象,可以通过该对象获取结果 */ private fun testAsync(){ //runBlocking会阻塞线程,等待异步返回的结果 runBlocking { println("${getTime()} fetchData a1 ------") var resul1 = fetchData() println("${getTime()} fetchData a2 resul1 : ${resul1}") } println("${getTime()} ------------- testAsync ----------") runBlocking { //在线程中开启子协程 var job2 = CoroutineScope(Dispatchers.IO).async { println("${getTime()} fetchData b1 ------") var result2 = fetchData() println("${getTime()} fetchData b3 result2 : ${result2}") "my job2 resul2 ${result2}" } //b1和b2,没有固定的执行顺序,所以async和job2.await()之间,不要执行任何语句 println("${getTime()} fetchData b2 job2 : ${job2}") //会等待fetchData()执行完成,再执行后面的语句,等待async返回的结果 var job2Result = job2.await() println("${getTime()} fetchData b4 ${job2Result}") } println("${getTime()} -------22------ testAsync ------22----") //可以异步调用,但是没有不能使用fetchData返回结果,得处理suspend var job3 = CoroutineScope(Dispatchers.IO).async { var result3 = fetchData() "my job3 result3 ${result3}" } //不能使用await, //var job3Result = job3.await() println("${getTime()} fetchData job3 ${job3}") } /** * delay:延迟操作,挂起函数 */ private suspend fun testDelay(){ runBlocking { delay(1000) var result1 = fetchData() } MainScope().launch { delay(100) } CoroutineScope(Dispatchers.IO).launch{ delay(100) } GlobalScope.launch { delay(100) } } private fun testWithContext(){ runBlocking { //更新UI withContext(Dispatchers.IO){ } //执行异步耗时任务 withContext(Dispatchers.IO){ fetchData() } } } private suspend fun fetchData() : String{ println("${getTime()} fetchData aa ") delay(1000) return "数据加载中。。。" } private fun getTime() : String{ val currentDateTime = LocalDateTime.now() val currentFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss SSS") val formatDateTime = currentDateTime.format(currentFormat) return formatDateTime } }