代码变得十分简单优雅~
这就是传说中的 非阻塞式挂起的魅力。这个概念很后面再说。
注:它和Dart语言中的那个不一样哦。
因为其使用lambda表达式,所以代码风格简洁,效率又高,下面一节可读可不读。
该节可读可不读。
注:Kotlin出现时,Java还在6/7,这也是为什么Kotlin从一开始就被提倡应用于Android开发的一个小小的原因(因为Java还没有Lambda表达式)
在使用协程(以及很大一部分代码块)的时候,我们经常会用到Lambda表达式。
我们为什么用它?
-
简洁好写
-
减少样板代码
但是你以为这就是它的好处吗?我之前一直搞不懂为什么仅仅是实现一个函数式编程,却能成为Java8新特性中必须要吹、必须要学的知识,而究其原因其实是:
Lambda函数(如果不捕获)在运行时产生,在使用时作为单例对象(私有方法)存在,重用时不会产生其他开销,而匿名内部类则在每次调用都要加载并实例化成一个对象。
这句话有点高度概括。
需要知道Java是如何去编译匿名内部类的,在我之前学习热修复的时候热修复原理学习(3)编译器与语言特性的影响学习过 内部类在编译期会被编译为跟外部类一样的顶级类,匿名内部类也是内部类,所以它会走和类一样的加载-使用-垃圾回收的过程,而Lambda表达式则是在运行时产生一个调用的函数入口。
所以使用 Lambda表达式 是完爆 使用匿名内部类的。
这里的捕获指的是该Lambda使用了其作用域之外的变量,可以将其视为私有字段的类中的函数,而不捕获指的Lambda就是纯函数。
================================================================================
在Kotlin本来的包中时没有协程api的,所以要在build.gradle中引入:
// build.gradle
implementation “org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version”
implementation “org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version”
协程的入口是 launch{}
语句块,但它不是顶层函数,所以不能直接使用,有三种实现,分别来看看他们来实现Hello World
使用 GlobalScope.launch
可以手动开启一个协程:
fun main() {
println(“Thread name:” + Thread.currentThread().name)
GlobalScope.launch { // 在后台启动一个新的协程并继续
println(“Coroutines Thread name:” + Thread.currentThread().name)
delay(100L) // 假设这是一个100ms耗时任务
println(“World!”) // 这是耗时任务的结果
}
println(“Hello,”) // 主线程中的代码会立即执行
Thread.sleep(200L) // 延迟 200 毫秒来保证 JVM 的存活
}
// 打印:
Thread name:main
Hello,
Coroutines Thread name:DefaultDispatcher-worker-1
World!
在开启的协程中,我们使用 delay来让协程挂起100ms后答应world,表明这是一个耗时的任务。
主线程中输入了Hello后,使用Thread.sleep()
来阻塞主线程,防止在协程的任务还没执行完时,主线程就关闭了。
这个时候我们会发现,协程所在的线程和外边线程不一致。
runBlocking{..}
代码块里面,就是协程。相比于GlobalScope,它是阻塞线程的,一般开发中我们用不到,常用于单元测试,来看一下使用语句块实现:
fun main() {
println(“Thread name:” + Thread.currentThread().name)
runBlocking {
println(“Coroutines Thread name:” + Thread.currentThread().name)
delay(1000L)
print("Hello, ")
}
print(“World!”)
}
// 打印结果:
Thread name:main
Coroutines Thread name:main
Hello, World
可以看到 runBlocking{...}
开启了一个协程,但是他没有在新线程里面执行,而是一直阻塞到里面的代码块完成。
可以来看下下面的用法:
fun main() = runBlocking { // 使用runBlocking开启一个协程
launch { // 里面再开启一个协程
delay(1000L)
println("World! " + Thread.currentThread().name)
}
println("Hello, " + Thread.currentThread().name)
}
// 打印结果:
Hello, main
World! main
这个代码中,我们在 runBlocking{}
里,又开启了一个launch协程,相当于大协程里面的小协程。
我们没有使用 Thread.sleep()
来防止主线程执行完而launch中的代码还没有执行的问题,它依然能够等所有任务都执行完后才关闭程序。
上面两片代码可