kotlin-协程基本操作

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
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Android-Flutter

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值