协程:协程的目的是为了让多个任务之间更好的协作,解决异步回调嵌,能够以同步的方式编排代码完成异步工作。将异步代码像同步代码一样直观。同时它也是一个并发流程控制的解决方案。
1.怎么启动协程
协程的启动如下

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
}

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
}

常见的协程创建方法有

launch是一个CoroutineScope的扩展方法在不阻塞当前线程的情况下启动一个新的协程,并返回Job对象。job对象可以看作协程本身,包含了对协程的控制方法

async方法返回Deffered是job的子类,实际上就是增加了awiat方法,能够让当前协程暂时挂起,暂停往下执行,当await方法有返回值后,会恢复协程,继续往下执行。

Deffered和job都有的方法有

start()手动启动协程

join()等待协程执行完毕

cancel()取消一个协程

CoroutineScope是一个接口,我们通常使用它的实现类GlobalScope这是一个全局的变量。上述方法中第一个参数context是协程的上下文如果我们不传默认会使用EmptyCoroutineContext,经过 newCoroutineContext(context)会返回Default协程运行调度器。


Disaptchers.IO 显示的指定协程运行的线程为IO线程

Dispathcers.Main 指定这个协程运行在主线程上。

Dispathcers.Default 默认的,启动协程时会启动一个线程

Dispathcers.Unconfined 不指定,在当前线程运行,协程恢复后的运行的线程取决于协程关起时所在的线程。

在协程调度器中needDispatch()方法表示是否需要将协程代码块分发到相应的线程中,其中只有Unconfined不需要分发,因为他是运行在当前线程中。

第二个参数是协程启动的类型

DEFAULT模式表示创建即启动,可随时取消。

ATOMIC自动模式,创建即启动,但是启动前不可取消。

LAZY模式只用当调用start方法后才会启动。

最后一个参数则是我们的闭包代码块

我们来看一下代码

private val TAG = "CoroutineScene"

private suspend fun request1() : String{
    delay(2000)
    Log.e(TAG, "request1 work on Thread ${Thread.currentThread().name}")
    return "request1"
}

private suspend fun request2() : String{
    delay(2000)
    Log.e(TAG, "request2 work on Thread ${Thread.currentThread().name}")
    return "request2"
}

private suspend fun request3(str : String = "") : String{
    delay(2000)
    Log.e(TAG, "request3 work on Thread ${Thread.currentThread().name}")
    return "request3"
}



/**
 * 这种写法异步任务按书写顺序执行
2022-09-02 15:18:38.641 6163-6163/com.example.tdframe E/CoroutineScene: coroutine1
2022-09-02 15:18:38.641 6163-6163/com.example.tdframe E/CoroutineScene: run coroutine1
2022-09-02 15:18:40.645 6163-6163/com.example.tdframe E/CoroutineScene: request1 work on Thread main
2022-09-02 15:18:42.649 6163-6163/com.example.tdframe E/CoroutineScene: request2 work on Thread main
2022-09-02 15:18:44.653 6163-6163/com.example.tdframe E/CoroutineScene: request3 work on Thread main
2022-09-02 15:18:44.653 6163-6163/com.example.tdframe E/CoroutineScene: updateUI r1=request1, r2 = request2, r3 = request3 Thread main
 代码是运行在UI线程上的,延迟代码运行在IO线程
 */
fun coroutine1(){
    GlobalScope.launch(context = Dispatchers.Main) {
        Log.e(TAG, "run coroutine1")
        val r1 = request1()
        val r2 = request2()
        val r3 = request3(r2)
        updateUI(r1, r2, r3)
    }
    Log.e(TAG, "coroutine1")
}

上面的代码使用的协程调度器为 Dispatchers.Main从上面的日志中可以看到Log.e(TAG, “coroutine1”)闭包代码块之外的代码是在之前被低昂用的,因为 Dispatchers.Main最后是通handler让协程运行在主线程上。

/**
2022-09-02 15:36:04.386 6163-6163/com.example.tdframe E/CoroutineScene: coroutine1
2022-09-02 15:36:04.386 6163-6443/com.example.tdframe E/CoroutineScene: run coroutine1, ThreadDefaultDispatcher-worker-1
2022-09-02 15:36:06.388 6163-6443/com.example.tdframe E/CoroutineScene: request1 work on Thread DefaultDispatcher-worker-1
2022-09-02 15:36:08.389 6163-6443/com.example.tdframe E/CoroutineScene: request2 work on Thread DefaultDispatcher-worker-1
2022-09-02 15:36:10.392 6163-6443/com.example.tdframe E/CoroutineScene: request3 work on Thread DefaultDispatcher-worker-1
2022-09-02 15:36:10.392 6163-6443/com.example.tdframe E/CoroutineScene: updateUI r1=request1, r2 = request2, r3 = request3 Thread DefaultDispatcher-worker-1
 */
fun coroutine1(){
    GlobalScope.launch(context = Dispatchers.Default) {
        Log.e(TAG, "run coroutine1, Thread${Thread.currentThread().name}")
        val r1 = request1()
        val r2 = request2()
        val r3 = request3(r2)
        updateUI(r1, r2, r3)
    }
    Log.e(TAG, "coroutine1")
}

这是调度器为Dispatchers.Default代码运行在自带的线程中。

/**
2022-09-02 15:42:20.969 6163-6163/com.example.tdframe E/CoroutineScene: run coroutine1, Threadmain
2022-09-02 15:42:20.969 6163-6163/com.example.tdframe E/CoroutineScene: coroutine1
2022-09-02 15:42:22.972 6163-6705/com.example.tdframe E/CoroutineScene: request1 work on Thread kotlinx.coroutines.DefaultExecutor
2022-09-02 15:42:24.974 6163-6705/com.example.tdframe E/CoroutineScene: request2 work on Thread kotlinx.coroutines.DefaultExecutor
2022-09-02 15:42:26.976 6163-6705/com.example.tdframe E/CoroutineScene: request3 work on Thread kotlinx.coroutines.DefaultExecutor
2022-09-02 15:42:26.976 6163-6705/com.example.tdframe E/CoroutineScene: updateUI r1=request1, r2 = request2, r3 = request3 Thread kotlinx.coroutines.DefaultExecutor
 */
fun coroutine1(){
    GlobalScope.launch(context = Dispatchers.Unconfined) {
        Log.e(TAG, "run coroutine1, Thread${Thread.currentThread().name}")
        val r1 = request1()
        val r2 = request2()
        val r3 = request3(r2)
        updateUI(r1, r2, r3)
    }
    Log.e(TAG, "coroutine1")
}

这是调度器为Dispatchers.Unconfined代码运行的情况,
Log.e(TAG, “run coroutine1, Thread${Thread.currentThread().name}”)这句代码因为是在主线程上调用的所有打印出来是在MainThread上,但是request1中的代码为什么没有运行在住线程中呢

private suspend fun request1() : String{
    delay(2000)
    Log.e(TAG, "request1 work on Thread ${Thread.currentThread().name}")
    return "request1"
}

因为在request1中我们调用了delay方法,delay方法是在一个默认的线程池中调用,代码执行到delay协程将会被挂起,之后延时结束后将会被恢复,以回调的方式执行接下来的代码。
关于协程的挂起和恢复我将在下一章讲解。

对于Android,jetPack建议我们使用如下方式使用协程,和宿主的生命周期绑定

/**
     * E/CoroutineScene: =================onCreate===================
    E/CoroutineScene: lifecycleScope.launchWhenCreated:whenCreated
    E/CoroutineScene: lifecycle.coroutineScope.launchWhenCreated:whenCreated
    E/CoroutineScene: =================onStart===================
    E/CoroutineScene: lifecycleScope.launchWhenStarted:whenCreated
    E/CoroutineScene: lifecycle.coroutineScope.launchWhenStarted:whenCreated
    E/CoroutineScene: =================onResume===================
    E/CoroutineScene: lifecycleScope.launchWhenResumed:whenCreated
    E/CoroutineScene: lifecycleScope.launchWhenResumed:whenResumed
    lifecycleScope.launchWhenResumed:whenStarted
    E/CoroutineScene: lifecycle.coroutineScope.launchWhenResumed:whenCreated
    lifecycle.coroutineScope.launchWhenResumed:whenResumed
    lifecycle.coroutineScope.launchWhenResumed:whenStarted
    E/CoroutineScene: lifecycleScope.launchWhenCreated:whenResumed
    lifecycleScope.launchWhenCreated:whenStarted
    E/CoroutineScene: lifecycle.coroutineScope.launchWhenCreated:whenResumed
    lifecycle.coroutineScope.launchWhenCreated:whenStarted
    lifecycleScope.launchWhenStarted:whenResumed
    E/CoroutineScene: lifecycleScope.launchWhenStarted:whenStarted
    lifecycle.coroutineScope.launchWhenStarted:whenResumed
    E/CoroutineScene: lifecycle.coroutineScope.launchWhenStarted:whenStarted
     */
    lifecycleScope.launchWhenCreated {
        whenCreated {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenCreated:whenCreated")
        }
        whenResumed {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenCreated:whenResumed")
        }
        whenStarted {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenCreated:whenStarted")
        }
    }

    lifecycle.coroutineScope.launchWhenCreated {
        whenCreated {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenCreated:whenCreated")
        }
        whenResumed {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenCreated:whenResumed")
        }
        whenStarted {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenCreated:whenStarted")
        }
    }
    lifecycleScope.launchWhenResumed {
        whenStarted {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenResumed:whenCreated")
        }
        whenResumed {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenResumed:whenResumed")
        }
        whenStarted {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenResumed:whenStarted")
        }
    }
    lifecycle.coroutineScope.launchWhenResumed {
        whenStarted {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenResumed:whenCreated")
        }
        whenResumed {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenResumed:whenResumed")
        }
        whenStarted {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenResumed:whenStarted")
        }
    }
    lifecycleScope.launchWhenStarted {
        whenStarted {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenStarted:whenCreated")
        }
        whenResumed {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenStarted:whenResumed")
        }
        whenStarted {
            Log.e("CoroutineScene", "lifecycleScope.launchWhenStarted:whenStarted")
        }
    }

    lifecycle.coroutineScope.launchWhenStarted {
        whenStarted {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenStarted:whenCreated")
        }
        whenResumed {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenStarted:whenResumed")
        }
        whenStarted {
            Log.e("CoroutineScene", "lifecycle.coroutineScope.launchWhenStarted:whenStarted")
        }
    }
}