Kotlin协程Api用例详解

Kotlin协程

有些 APIs 是需要长时间运行,并且需要调用者阻塞直到这些调用完成(比如网络 IO ,文件 IO ,CPU 或者 GPU 比较集中的工作)。协程提供了一种避免线程阻塞并且用一种更轻量级,更易操控到操作:协程暂停。

添加Kotlin协程依赖
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5"

1、挂起函数

当一个函数被 suspend 修饰时表示可以被挂起,调用它会导致挂起协程,挂起函数可以和正常函数那样接受参数返回结果,但只能在协程中调用或着被其他挂起函数调用。

suspend fun doSomething(){
        //do something
        delay(1000)
    }

因为delay为Kotlin封装的挂起函数,所以调用delay的函数也必须是挂起函数。

2、协程Api

在已有的Api中,Kotlin提供了两种方式实现协程 async/Deferred和launch/Job

public actual fun  async(
    context: CoroutineContext = DefaultDispatcher,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    parent: Job? = null,
    block: suspend CoroutineScope.() -> T
): Deferred {
    val newContext = newCoroutineContext(context, parent)
    val coroutine = if (start.isLazy)
        LazyDeferredCoroutine(newContext, block) else
        DeferredCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
public expect fun launch(
    context: CoroutineContext = DefaultDispatcher,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    parent: Job? = null,
    block: suspend CoroutineScope.() -> Unit
): Job

从源码中可以看出async和launch的参数列表中只有最后一个参数:带有 suspend 修饰的函数类型不同,async中的lambda有返回值,和Deferred的类型相同。launch中的lambda没有返回值。

  async(UI) {
            val deferred = async(CommonPool) {
                //do something
                delay(1000)
                "stop"
            }
            deferred.await()
        }

3、context

两个Api的构造函数中,第一个参数为context。在android开发中比较常用的两个为UI何CommonPool。

UI为主线程,UI线程,只有context是UI的launch或者async的block lambda中才能更新UI

CommonPool为公共的线程池,在context是CommonPool的lauch或者async中的block lambda中可以异步处理耗时操作。

launch(UI) { 
            text.setText("UI")
        }
async(UI) { 
            text.setText("UI")
        }
launch(CommonPool) { 
            delay(1000)
        }
async(CommonPool) { 
            delay(1000)
        }

4、async/Deferred

   async{
            loge(message = "outer start")
            val inner = async{
                loge(message = "inner start")
                //do something
                delay(1000)
                loge(message = "inner stop")
                "stop"
            }
            loge(message = "outer wait itself start")
            delay(500)
            loge(message = "outer wait itself stop")
            loge(message = "outer wait inner")
            val await = inner.await()
            loge(message = "outer stop")
            await
        }
//        依次打印
//        16:30:41.759 14668-14737/com.moo.demogo E/DemoGo: outer start
//        16:30:41.761 14668-14737/com.moo.demogo E/DemoGo: outer wait itself start
//        16:30:41.768 14668-14737/com.moo.demogo E/DemoGo: inner start
//        16:30:42.268 14668-14738/com.moo.demogo E/DemoGo: outer wait itself stop
//        16:30:42.268 14668-14738/com.moo.demogo E/DemoGo: outer wait inner
//        16:30:42.771 14668-14738/com.moo.demogo E/DemoGo: inner stop
//        16:30:42.772 14668-14738/com.moo.demogo E/DemoGo: outer stop
从打印的信息可以看出outer(外层async)开始线性调用,打印outer start,在inner创建之后inner也开始执行,(outer wait itself start打印在inner start之前是因为inner async在创建的过程中会耗费极少的时间,而在这段时间内outer已经执行到下一步,理论上在inner创建之后,inner和outer之后都是同步执行)当outer等待500ms之后 outer打印outer wait itself stop同时开始等待inner,打印outer wait inner,下面这句代码val await = inner.await() 为Kotlin协程重点。正常情况下,outer会直接打印outer stop,之后等待500ms之后 inner stop。但是由于inner.await(),outer会挂起,等待inner执行结束,返回字符串“stop”之后,outer再结束,这也就是为什么最后是outer wait inner 500ms之后inner stop 然后才是outer stop

5、launch/Job

launch{
            loge(message = "outer start")
            val inner = launch{
                loge(message = "inner start")
                //do something
                delay(1000)
                loge(message = "inner stop")
            }
            loge(message = "outer wait itself start")
            delay(500)
            loge(message = "outer wait itself stop")
            loge(message = "outer wait inner")
            inner.join()
            loge(message = "outer stop")
        }
//        依次打印
//        16:57:05.431 20131-20298/com.moo.demogo E/DemoGo: outer start
//        16:57:05.432 20131-20298/com.moo.demogo E/DemoGo: outer wait itself start
//        16:57:05.432 20131-20300/com.moo.demogo E/DemoGo: inner start
//        16:57:05.940 20131-20298/com.moo.demogo E/DemoGo: outer wait itself stop
//        16:57:05.940 20131-20298/com.moo.demogo E/DemoGo: outer wait inner
//        16:57:06.439 20131-20298/com.moo.demogo E/DemoGo: inner stop
//        16:57:06.441 20131-20300/com.moo.demogo E/DemoGo: outer stop
打印信息和async/Deferred一致,区别在与lauch返回Job,挂起方法为job.join()且没有返回值。

async和launch可以根据是否需要返回值这一特点选择使用或者混合使用
launch {
            loge(message = "outer start")
            val inner = async {
                loge(message = "inner start")
                //do something
                delay(1000)
                loge(message = "inner stop")
                "stop"
            }
            loge(message = "outer wait itself start")
            delay(500)
            loge(message = "outer wait itself stop")
            loge(message = "outer wait inner")
            val await = inner.await()
            //deal result await
            loge(message = "outer stop")
        }

你可能感兴趣的:(Kotlin)