Kotlin协程入门到实战全部三篇文章:
- Kotlin协程Coroutines入门到实战:(一)理解异步回调的本质
- Kotlin协程Coroutines入门到实战:(二)Coroutines初体验
- Kotlin协程Coroutines入门到实战:(三)Coroutines+Retrofit+ViewModel+LiveData实现MVVM客户端架构
上一篇文章中我们对异步回调的本质做了比较深入的探讨,最终得出了异步回调就是代码的多线程顺序执行”的结论。接着引出了Kotlin协程可以实现顺序编写异步代码,自动进行线程切换的作用。既然Kotlin协程那么神奇,那具体该如何使用呢?
1.添加依赖
Kotlin协程不属于Kotlin语言本身,使用之前必须手动引入。在Android平台上使用可以添加Gradle依赖:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1'
2.启动协程
首先看下如下代码:
GlobalScope.launch {
delay(1000L)
println("Hello,World!")
}
上述代码使用launch方法启动了一个协程,launch后面的花括号就是协程,花括号内的代码就是运行在协程内的代码。
接着来深入了解一下launch方法的声明:
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit): Job {
...}
可以看到launch方法是CoroutineScope
的拓展方法,也就是说我们启动协程要在一个指定的CoroutineScope
上来启动。CoroutineScope
翻译过来就是“协程范围”,指的是协程内的代码运行的时间周期范围,如果超出了指定的协程范围,协程会被取消执行,上面第一段代码中的GlobalScope
指的是与应用进程相同的协程范围,也就是在进程没有结束之前协程内的代码都可以运行。除此之外为了方便我们的使用,在Google的Jetpack中也提供了一些生命周期感知型协程范围。实际开发中我们可以方便地选择适当的协程范围来为耗时操作(网络请求等)指定自动取消执行的时机,详情见:https://developer.android.google.cn/topic/libraries/architecture/coroutines
接着可以看下launch方法的其他参数:
context
:协程上下文,可以指定协程运行的线程。默认与指定的CoroutineScope
中的coroutineContext
保持一致,比如GlobalScope
默认运行在一个后台工作线程内。也可以通过显示指定参数来更改协程运行的线程,Dispatchers
提供了几个值可以指定:Dispatchers.Default
、Dispatchers.Main
、Dispatchers.IO
、Dispatchers.Unconfined
。start
:协程的启动模式。默认的(也是最常用的)CoroutineStart.DEFAULT
是指协程立即执行,除此之外还有CoroutineStart.LAZY
、CoroutineStart.ATOMIC
、CoroutineStart.UNDISPATCHED
。block
:协程主体。也就是要在协程内部运行的代码,可以通过lamda
表达式的方式方便的编写协程内运行的代码。CoroutineExceptionHandler
:除此之外还可以指定CoroutineExceptionHandler
来处理协程内部的异常。
返回值Job
:对当前创建的协程的引用。可以通过Job
的start
、cancel
、join
等方法来控制协程的启动和取消。
启动协程不是只有launch
一个方法的,还有async
等其他方法可以启动协程,不过launch
是最常用的一种方法,其他的方法大家可以去自行了解。
3.调用挂起函数
回到上面的代码:
println("Start")
GlobalScope.launch(Dispatchers.Main) {
delay(1000L)
println("Hello World")
}
println("End")
首先通过GlobalScope.launch
启动了一个协程,这里指定协程运行的线程为主线程,接着协程内只有两行代码,协程启动之后就立即执行。首先直接输出了"Start"和"End",接着1秒钟后又输出了"Hello World"。这结果看起来看似顺理成章,因为我们使用非常相似的Thread
相关的代码也完全可以实现以上代码的效果:
println("Start")
Thread {
Thread.sleep(1000L