AndroidのKotlin协程
2020-02-05 本文已影响0人
耑意儿
目录:
1. 协程Coroutines基础
2. 协程 - 超时与取消
3. 协程 - 结合挂起函数
Android小仙
1.协程Coroutines基础
1.1 GlobalScope.launch
启动一个独立协程
1.2 runBlocking
协程构建器构建一个协程
1.3 fun main() = runBlocking<Unit>{}
将一个函数构建为协程函数
1.4 delay( 1000L )
协程的挂起函数,只能在协程中使用。不会造成线程挂起
- 如果一个函数不返回任何有用的值,那么他的返回类型为Unit,Unit是一种只有一个值Unit的类型,该值不需要显示返回
- <Unit>可写可不写,可显示返回,也可不显示返回
- 栗子1
GlobalScope.launch
启动一个子协程,主函数通过runBlocking
调用delay
函数以保活JVM
fun main(){
GlobalScope.launch {
// delay 是一个特殊的挂起函数,只能在协程中使用,它不会造成线程阻塞,但是会挂起协程,
delay(1000)
println("123")
}
println("Lisa Go")
// Thread.sleep(3000)
// 阻塞主线程3秒钟
runBlocking {
delay(3000)
println("abc")
}
print("Lisa Stop")
}
- 栗子2 将主函数构建为协程
/**
* 调用协程构建器runBlocking函数,将主函数构建为协程,返回类型为Unit
**/
fun main() = runBlocking<Unit>{
// 需要保证的是,JVM在协程未执行完毕之前保持存活状态
// 开启一个协程(子线程),子线程延迟1秒后打印123
GlobalScope.launch {
// delay 是一个特殊的挂起函数,只能在协程中使用,它不会造成线程阻塞,但是会挂起协程,
delay(1000)
println("123")
}
println("Lisa Go")
// 此时,主线程已经是一个协程,不必再调runBlocking,直接调delay函数
delay(3000)
println("abc")
print("Lisa Stop")
}
1.5 join
函数将子协程加入主协程中
- 栗子3 调用协程的
join
函数,实现JVM保活,省去delay
函数
// 有趣的是,尽管subThread在最后才调用join方法,
// 但是在main执行1秒后先执行了333,而Lisa Finish在延迟2秒后才执行
fun main() = runBlocking {
println("Lisa Go!")
val subThread = GlobalScope.launch {
delay(1000)
println("333")
}
println("Lisa Finish")
subThread.join()
}
1.6 结构化并发:在顶层协程的作用域内启动协程
- 栗子4
runBlocking
协程中的launch替代GlobalScope.launch
,实现JVM保活
// 通过在外部协程作用域内启动协程的方法,我们可以省去调用join的步骤
// 主线程会等到外部协程作用域内启动的所有协程执行完毕后才被销毁
fun main() = runBlocking {
// GlobalScope.launch {
launch {
delay(1000)
println("123")
}
println("Lisa Go")
}
1.7 作用域构建器:coroutineScope
- 栗子5
coroutineScope
创建的协程作用域在所有已启动的子协程未执行完毕之前不会执行到下一行代码。切换注释coroutineScope
代码块跟踪打印情况
// 这个构建器影响了一堆代码,abc不再是最先打印出来的
// coroutineScope创建了一个协程作用域,并且在所有已启动的子协程未执行完毕之前不会结束
// 这就意味着在coroutineScope之后的代码在该作用域内启动的所有子协程未执行完毕之前不会被执行到
fun main() = runBlocking { // this: CoroutineScope
launch {
delay(3000L)
println("111")
}
launch {
delay(4000L)
println("222")
}
println("YoHoo")
coroutineScope { // 创建一个协程作用域
launch {
delay(5000L)
println("inner 111")
}
launch {
delay(3000L)
println("inner 222")
}
delay(1000L)
println("inner abc")
}
// coroutineScope {
// launch {
// println("inner 111")
// }
// println("inner abc")
// }
launch {
delay(3000L)
println("333")
}
println("abc")
}
1.8 挂起函数
- 栗子6 被
suspend
修饰的函数为挂起函数,挂起函数只能被协程或被另一个挂起函数调用
// 提取launch协程中的代码,抽出一个挂起函数,挂起函数被suspend修饰
fun main() = runBlocking {
launch {
suspendFun()
}
println("abc")
}
// 挂起函数只能被协程或者被另一个挂起函数调用!
suspend fun suspendFun(){
delay(3000)
println("123")
}
1.9 协程超轻量
- 使用顶层协程启动子协程,循环会按顺序走
- 栗子7
repeat
实现代码循环1000次
// 存在打印遗漏,且打印顺序错乱
fun main2(){
repeat(10000){ i ->
GlobalScope.launch {
println("123: "+i+" 次")
delay(1000)
}
}
}
// 不会漏,而且按顺序走流程
fun main() = runBlocking{
repeat(10000){ i ->
launch {
println("123: "+i+" 次")
delay(1000)
}
}
}
2. 协程 - 超时与取消
2.1 超时限制
fun main() = runBlocking{
try{
withTimeout(1500){
repeat(10){i ->
launch {
delay(500)
println("yoyoo :"+i)
}
}
}
}catch (excep : TimeoutCancellationException) {
println("catch exception")
}finally {
println("do finally")
}
}
2.2 取消协程
fun main() = runBlocking {
val job = launch {
withTimeoutOrNull(3000){
repeat(10){ i ->
delay(500)
println("111 "+i)
}
}
}
println("ready to cancel")
delay(1200)
job.cancel()
println("after cancel")
}