Kotlin Coroutine(协程)系列:
1. Kotlin Coroutine(协程) 简介
2. Kotlin Coroutine(协程) 基本知识bash
这篇文章主要介绍协程中的一些基本概念。网络
Kotlin
中提供了关键字suspend
用来描述一个函数为挂起函数,写法以下:async
//官方提供的函数
suspend fun delay(timeMillis: Long) {
...
}
复制代码
以上写法就表明delay
函数为一个挂起函数。函数
在前面一篇文章Kotlin Coroutine(协程) 简介中我提到过挂起函数只会挂起当前协程,不会挂起阻塞当前协程所处的线程。事实上,想要执行协程就至少须要一个挂起函数,所以挂起函数是协程中一个很是重要的概念。post
suspend
能够将普通函数、扩展函数、lambda表达式均标记为挂起函数官方描述:为协程定义了一个范围this
Defines a scope for new coroutines.spa
也能够理解为协程的上下文环境,更通俗点你能够将其看做为一个协程。.net
咱们再来看下官方源码中的定义:线程
public interface CoroutineScope {
/** * Context of this scope. */
public val coroutineContext: CoroutineContext
}
复制代码
经过这个代码咱们能够看到CoroutineScope
初始定义中只有一个协程上下文CoroutineContext
对象,因此协程的上下文对象实际上是由CoroutineContext
决定的,所以将CoroutineScope
看做协程更好理解。code
协程上下文,包含了协程中的一些元素,主要有Job
和CoroutineDispatcher
协程的后台任务,它有本身的生命周期,该任务能够被取消。
Job
能够有父Job
,当父Job
被取消时,其全部子Job
也会被取消。
Job
有三种状态:
isActive
是否处于活动状态isCompleted
是否完成isCancelled
是否被取消可参考下表:
State | [isActive] | [isCompleted] | [isCancelled] |
---|---|---|---|
New (optional initial state) | false |
false |
false |
Active (default initial state) | true |
false |
false |
Completing (transient state) | true |
false |
false |
Cancelling (transient state) | false |
false |
true |
Cancelled (final state) | false |
true |
true |
Completed (final state) | false |
true |
false |
当建立协程开始执行并获取到Job
对象后,若是想等该协程执行结束再执行其余的业务逻辑,那么能够调用Job.join()
方法,该方法会等待该协程任务执行结束,该方法为挂起函数。
它是Job
的子类,与Job
不一样的是它能够有返回值,而Job
是没有返回值的。
经过调用Deferred
的await()
方法便可拿到返回值,而await()
方法也是一个挂起函数,所以调用该方法时会挂起当前协程,直到拿到返回值协程从新恢复执行。
Android
中协程结合Retrofit
发起网络请求能够考虑使用该类获取请求结果
协程调度器,它能够将协程的执行局限在指定的线程中,它有四个默认的实现:
Dispatchers.Default
默认调度器,在使用launch
和async
等协程构造器建立协程时,若是不指定调度器则会使用此默认调度器,该调度器会让协程在JVM
提供的共享线程池中执行Dispatchers.Main
主线程调度器,让协程在主线程即UI线程中执行Dispatchers.IO
让协程在IO线程(子线程)中执行,该调度器会与Dispatchers.Default
调度器共享同一个线程池Dispatchers.Unconfined
该调度器不指定协程在某个线程中执行。设置了该调度器的协程会在调用者线程中启动执行直到第一个挂起点,挂起后,它将在挂起函数执行的线程中恢复,恢复的线程彻底取决于该挂起函数在哪一个线程执行。newSingleThreadContext
这是Kotlin
另外提供的一个调度器,它会为协程启动一个新的线程。一个专用的线程是一种很是昂贵的资源。 在真实的应用程序中二者都必须被释放,当再也不须要的时候,使用 close 函数,或存储在一个顶级变量中使它在整个应用程序中被重用。另外须要注意的是:协程调度器默认承袭外部协程的调度器。
这是一个全局的CoroutineScope
不会受任何Job约束,经过它建立的是全局协程,它会在整个应用的生命周期中运行,不能被取消
这是一个扩展的CoroutineScope
实例方法,同时也是一个很经常使用的协程构建器。
经过其默认参数会建立一个不会阻塞当前线程且会当即执行的协程,该方法会返回一个Job
对象,该方法默认承袭所在的CoroutineScope
对象的调度器。
val scope = CoroutineScope(Dispatchers.Main + Job())
scrope.launch {
//协程实现
}
复制代码
上述代码经过launch
建立的协程会在UI线程中执行
val scope = CoroutineScope(Dispatchers.Main + Job())
scrope.launch(Dispatchers.IO) {
//协程实现
}
复制代码
上述代码经过launch
建立的协程会在IO线程中执行
这是一个全局的协程构建器,能够在任何地方调用。
该构建器会建立一个阻塞当前线程的协程,因此该构建器不建议使用在协程内。
和launch
函数同样,也是CoroutineScope
的扩展实例方法,它也是一个经常使用的协程构建器,不一样是它建立协程时返回的是Deferred
,经过Deferred
能够拿到执行结果
val a = async {
log("I'm computing a piece of the answer")
6
}
val b = async {
log("I'm computing another piece of the answer")
7
}
log("The answer is ${a.await() * b.await()}")
复制代码
全局函数
切换协程上下文,通常主要用来切换协程所在的线程环境,如从主线程切换到IO线程。
调用该方法不会建立新的协程,同时是一个挂起函数
该方法会有一个返回值,其返回值为withContext
中lambda表达式的返回值