如何启动Kotlin协程

Posted 且听真言

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何启动Kotlin协程相关的知识,希望对你有一定的参考价值。

启动协程的基本方式

1.GlobalScope.launch

代码示例:

fun testGlobalScope() 
    GlobalScope.launch 
        println("Coroutinue started!")
        delay(1000L)
        println("Hello World!")
    
    println("After launch!")
    Thread.sleep(2000L)
    println("Process end!")



/**
 * After launch!
 * Coroutinue started!
 * Hello World!
 * Process end!
 */
@DelicateCoroutinesApi
public object GlobalScope : CoroutineScope 
    /**
     * Returns [EmptyCoroutineContext].
     */
    override val coroutineContext: CoroutineContext
        get() = EmptyCoroutineContext
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job 
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine

launch函数是CoroutineScope的扩展函数,它有三个参数:

  1.  context: CoroutineContext = EmptyCoroutineContext, 第一个参数是协程上下文,它的默认值是 EmptyCoroutineContext,如果不传这个参数,默认就会使用 EmptyCoroutineContext。也可以传入 Kotlin 官方为我们提供的 Dispatchers,来指定协程运行的线程池。(Dispatchers.IO、Dispatchers.Unconfined、Dispatchers.Main)
  2. start: CoroutineStart = CoroutineStart.DEFAULT,第二个参数是协程的启动模式,默认值是CoroutineStart.DEFAULT,CoroutineStart 是一个枚举类,一共有:DEFAULT、LAZY、ATOMIC、UNDISPATCHED。
  3. block: suspend CoroutineScope.() -> Unit,第三个参数是函数类型block,它的类型是suspend CoroutineScope.() -> Unit。本质是一个挂起函数。
  4. 函数的返回值是一个 Job,它其实代表的是协程的句柄,并不能返回协程的执行结果。

2.runBlocking 启动协程

代码示例

fun testRunBlocking2() 
    runBlocking 
        println("Coroutinue started!")
        delay(1000L)
        println("Hello World!")
    
    println("After Launch")
    Thread.sleep(2000L)
    println("Process end")




/**
 * Coroutinue started!
 * Hello World!
 * After Launch
 * Process end
 */
@Throws(InterruptedException::class)
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T 
    contract 
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    
    val currentThread = Thread.currentThread()
    val contextInterceptor = context[ContinuationInterceptor]
    val eventLoop: EventLoop?
    val newContext: CoroutineContext
    if (contextInterceptor == null) 
        // create or use private event loop if no dispatcher is specified
        eventLoop = ThreadLocalEventLoop.eventLoop
        newContext = GlobalScope.newCoroutineContext(context + eventLoop)
     else 
        // See if context's interceptor is an event loop that we shall use (to support TestContext)
        // or take an existing thread-local event loop if present to avoid blocking it (but don't create one)
        eventLoop = (contextInterceptor as? EventLoop)?.takeIf  it.shouldBeProcessedFromContext() 
            ?: ThreadLocalEventLoop.currentOrNull()
        newContext = GlobalScope.newCoroutineContext(context)
    
    val coroutine = BlockingCoroutine<T>(newContext, currentThread, eventLoop)
    coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
    return coroutine.joinBlocking()

runBlocking是普通函数,第一个参数:context: CoroutineContext,协程上下文。第二个参数是函数类型,block: suspend CoroutineScope.() -> T,函数类型是有返回值类型 T 的,与 runBlocking 的返回值类型是一样的,runBlocking 其实是可以从协程当中返回执行结果的。

fun testRunBlocking() 
    val runBlockingResult = runBlocking 
        delay(500L)
        return@runBlocking "HaHa"
    
    println("result:$runBlockingResult")


result:HaHa

runBlocking特点:

  1. runBlocking 启动的协程会阻塞当前线程的执行。

3.async 启动协程

使用 async 创建协程,可以通过它返回的Deferred拿到协程的执行结果。

代码示例

fun testAsync() 
    runBlocking 
        val deferred = async 
            println("do async:$Thread.currentThread().name")
            delay(1000L)
            return@async "do completed"
        
        println("After async:$Thread.currentThread().name")
        val result = deferred.await()
        println("Result is: $result")
    


After async:main @coroutine#1
do async:main @coroutine#2
Result is: do completed
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> 
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyDeferredCoroutine(newContext, block) else
        DeferredCoroutine<T>(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine

async注意点

  1.  async 启动协程以后,不会阻塞当前程序的执行流程。
  2.  async的返回值,是一个 Deferred 对象,它的 await() 方法,就可以拿到协程的执行结果。
  3. await只是等待执行完,并不是触发执行。

以上是关于如何启动Kotlin协程的主要内容,如果未能解决你的问题,请参考以下文章

Android Kotlin回顾10.如何启动协程

Kotlin 多平台:如何在没有 runBlocking 的情况下以阻塞方式启动协程

kotlin 协程万字协程 一篇完成kotlin 协程进阶

Kotlin协程 - launch原理 笔记

kotlin协程硬核解读(4. 协程的创建和启动流程分析)

kotlin协程硬核解读(4. 协程的创建和启动流程分析)