美文网首页Android OtherKotlinKotlin-android
kotlin之协程(三),开始创建协程,launch,withC

kotlin之协程(三),开始创建协程,launch,withC

作者: 不思进取的码农 | 来源:发表于2020-11-02 14:29 被阅读0次

    目录

    kotlin之协程(一),线程,进程,协程,协程可以替换线程吗?
    kotlin之协程(二),Kotlin协程是什么、挂起是什么、挂起的非阻塞式
    kotlin之协程(三),开始创建协程,launch,withContext
    kotlin之协程(四),协程的核心关键字suspend
    kotlin之协程(五),launch 函数以及协程的取消与超时
    kotlin之协程(六),协程中的 async和launch的区别以及runBlocking
    kotlin之协程(七),协程中relay、yield 区别

    前言

    在开始做安卓之前都是学习如何用框架,用一个库,但是在用的过程中不了解核心本质,无法理解其含义.
    后来就换了学习的方法
    在用一个东西之前,都是先了解这个事物的本质,再去学习如何用,这样的形式可能在用的过程中有更深的体会.在使用的过程中再去更深入的了解其如何实现.

    我们想在kotlin使用协程

    项目中配置对 Kotlin 协程的支持

    在使用协程之前,我们需要在 build.gradle 文件中增加对 Kotlin 协程的依赖:

    • 项目根目录下的 build.gradle :
    buildscript {
    
        ext.kotlin_coroutines = '1.4.0'
    
    }
    
    • Module 下的 build.gradle
    dependencies {
    
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.0'
    
    }
    

    创建协程

    kotlin 中 GlobalScope 类提供了几个携程构造函数:

    • launch - 创建协程
    • async - 创建带返回值的协程,返回的是 Deferred 类
    • withContext - 不创建新的协程,指定协程上运行代码块
    • runBlocking - 不是 GlobalScope 的 API,可以独立使用,区别是 runBlocking 里面的 delay 会阻塞线程,而 launch 创建的不会

    先跑起来一个简单的例子:

    import kotlinx.coroutines.*
    
    fun main() {
        GlobalScope.launch { // 在后台启动一个新的协程并继续
            delay(1000L) // 非阻塞的等待 1 秒钟(默认时间单位是毫秒)
            println("World!") // 在延迟后打印输出
        }
        println("Hello,") // 协程已在等待时主线程还在继续
        Thread.sleep(2000L) // 阻塞主线程 2 秒钟来保证 JVM 存活
    }
    

    协程最简单的使用方法,其实在前面章节就已经看到了。我们可以通过一个 launch 函数实现线程切换的功能

    coroutineScope.launch(Dispatchers.IO) {
        ...
    }
    

    所以,什么时候用协程?当你需要切线程或者指定线程的时候。你要在后台执行任务?切!

    launch(Dispatchers.IO) {
        val image = getImage(imageId)
    }
    

    然后需要在前台更新界面?再切!

    coroutineScope.launch(Dispatchers.IO) {
        val image = getImage(imageId)
        launch(Dispatchers.Main) {
            avatarIv.setImageBitmap(image)
        }
    }
    

    好像有点不对劲?这不还是有嵌套嘛。

    如果只是使用 launch 函数,协程并不能比线程做更多的事。不过协程中却有一个很实用的函数:withContext 。这个函数可以切换到指定的线程,并在闭包内的逻辑执行结束之后,自动把线程切回去继续执行。那么可以将上面的代码写成这样:

    coroutineScope.launch(Dispatchers.Main) {      //  在 UI 线程开始
        val image = withContext(Dispatchers.IO) {  // 切换到 IO 线程,并在执行完成后切回 UI 线程
            getImage(imageId)                      // 将会运行在 IO 线程
        }
        avatarIv.setImageBitmap(image)             // 回到 UI 线程更新 UI
    } 
    

    我们甚至可以把 withContext 放进一个单独的函数里面:

    launch(Dispatchers.Main) {              //  在 UI 线程开始
        val image = getImage(imageId)
        avatarIv.setImageBitmap(image)     //  执行结束后,自动切换回 UI 线程
    }
    //                              
    fun getImage(imageId: Int) = withContext(Dispatchers.IO) {
        ...
    }
    

    这就是之前说的「用同步的方式写异步的代码」了。

    不过如果只是这样写,编译器是会报错的:

    fun getImage(imageId: Int) = withContext(Dispatchers.IO) {
        // IDE 报错 Suspend function'withContext' should be called only from a coroutine or another suspend funcion
    }
    

    意思是说,withContext 是一个 suspend 函数,它需要在协程或者是另一个 suspend 函数中调用。
    what?

    suspend函数我们在kotlin之协程(二),Kotlin协程是什么、挂起是什么、挂起的非阻塞式有提到,下一章我们专门讲解kotlin协程中的suspend

    (每天学习一点点.每天进步一点点,分享不宜路过点个赞呀,喜欢的点个关注后续更新不断)

    相关文章

      网友评论

        本文标题:kotlin之协程(三),开始创建协程,launch,withC

        本文链接:https://www.haomeiwen.com/subject/qhwkvktx.html