协程,全称能够译做协同程序,不少语言都有这个概念和具体实现,以前入门Python的时候接触过,而Kotlin其实也早就有这个扩展功能库了,只不过以前一直处于实验阶段,不过前段时间1.0的正式版终于出了,网上的相关博客也多了起来,通过这几天的学习我也来作下小结吧。android
首先贴下Kotlin协程的官方github地址kotlinx.coroutines,下面的配置都是参照这里的说明,并且里面还贴心的给咱们准备了不少基础的示例代码,感兴趣的的小伙伴稍后能够去看看。git
首先配置下Kotlin版本github
buildscript {
ext.kotlin_version = '1.3.11'
}
复制代码
而后引入依赖,目前最新版是1.1.0bash
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.0'
复制代码
配置很简单,接下来干什么呢。固然是写个协程版的Hello World
了!闭包
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // 建立并启动一个协程
delay(1000L) // 延迟(挂起)1000毫秒,注意这不会阻塞线程
println("World!") //延迟以后执行打印
}
println("Hello,") // 协程延迟的时候不会影响主线程的执行
Thread.sleep(2000L) // 阻塞线程2s,保证JVM存活,协程可正常执行完
}
复制代码
运行结果:ide
2018-12-23 17:35:16.998 15539-15539/com.renny.kotlin I/System.out: Hello,
2018-12-23 17:35:18.005 15539-18893/com.renny.kotlin I/System.out: World!
复制代码
上面的协程启动模式是默认的DEAFAULT
,也就是建立并当即启动的,咱们也能够设置启动模式为LAZY
,来本身安排是何时须要启动:函数
fun main() {
val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
println("World!")
}
println("Hello,")
job.start()
Thread.sleep(2000L)
}
复制代码
在我所采用的Kotlin 1.3版本中,还有ATOMIC
和UNDISPATCHED
两个额外的模式,可是如今仍是实验版,这里很少介绍。结果如上。CoroutineScope.launch
一共有三个参数,而后介绍其余两个:学习
context: CoroutineContext = EmptyCoroutineContext
:协程上下文block: suspend CoroutineScope.() -> Unit
:闭包参数,定义协程内须要执行的操做。返回值为Job对象。gradle
经过上面的例子,咱们知道了一个重要的点launch
函数是有返回值的,它是一个Job
的接口类型,除了配合LAZY
来本身启动一个协程,下面介绍下其余几个重要方法:ui
job.cancel()
取消一个协程fun main() {
val job = GlobalScope.launch {
delay(1000L)
println("World!")
}
job.cancel()
println("Hello,")
}
复制代码
协程被取消了,因此只打印了Hello,
join()
等待协程执行完毕fun main() = runBlocking {
val job = GlobalScope.launch {
delay(1000L)
println("World!")
delay(1000L)
}
println("Hello,")
job.join()
println("Good!")
}
复制代码
做用很像Thread.join()
函数,join()
后面的代码会等到协程结束再执行,结果以下:
2018-12-24 21:19:41.153 23484-23484/com.renny.kotlin I/System.out: Hello,
2018-12-24 21:19:42.148 23484-24172/com.renny.kotlin I/System.out: World!
2018-12-24 21:19:43.161 23484-23484/com.renny.kotlin I/System.out: Good!
复制代码
job.cancelAndJoin()
等待协程执行完毕而后再取消 这是一个 Job
的扩展函数,它结合了 cancel
和 join
的调用,来看下它的实现:public suspend fun Job.cancelAndJoin() {
cancel()
return join()
}
复制代码
细心的同窗可能发现了两个不通点,Job.join()
函数被一个名字叫runBlocking
的包围了,而Job.start()
和Job.cancel
都没有;Job.cancelAndJoin()
前面被一个特殊的关键词suspend
修饰了,这有什么用呢?
其实经过查看源码,Job.join()
也被suspend
修饰了,因此这是一个suspend
(挂起)函数,挂起函数必须在协程中或者挂起函数中使用,由于调用了Job.join()
,Job.cancelAndJoin()
也必须加上suspend
声明。事实上,要启动协程,必须至少有一个挂起函数。
协程及协程挂起:
协程是经过编译技术实现的,不须要虚拟机VM/操做系统OS的支持,经过相关代码来生效
协程的挂起几乎无代价,无需上下文切换或涉及OS
协程不能在随机指令中挂起,只能在挂起点挂起(调用标记函数)!
复制代码
上面咱们都是在线程中开启一个协程,一样在协程中咱们也能开启另外一个协程,因此咱们再来看下复杂点的例子:
fun main() = runBlocking {
GlobalScope.launch {
delay(1000L)
println("World!")
}
println("Hello,")
runBlocking {
delay(2000L)
}
}
复制代码
最外层的runBlocking
为最高级的协程 (通常为主协程), 其余协程如launch {}
由于层级较低能跑在runBlocking
里。runBlocking
的最大特色就是它的delay()
能够阻塞当前的线程,和Thread.sleep()
有着相同的效果。打印的日志同第一个示例。
Job类中会存储子协程的集合:
public val children: Sequence<Job>
复制代码
一样也提供了取消所有子协程的方法:
public fun Job.cancelChildren() {
children.forEach { it.cancel() }
}
复制代码
这篇主要介绍了协程引入Android项目的配置,协程的一些基本操做,挂起函数的概念,你们对协程有一个基本的概念,下一篇将讲下协程的更多知识。