news 2026/8/27 12:55:27

Kotlin语言基础入门到熟悉:Kotlin协程基础

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kotlin语言基础入门到熟悉:Kotlin协程基础

Kotlin语言基础入门到熟悉:Kotlin协程基础

1. 阻塞与非阻塞

runBlocking

delay是非阻塞的,Thread.sleep是阻塞的。显式使用runBlocking协程构建器来阻塞。

importkotlinx.coroutines.\*funmain(){GlobalScope.launch{// 在后台启动一个新的协程并继续delay(200)"rustfisher.com".forEach{print(it)delay(280)}}println("主线程中的代码会立即执行")runBlocking{// 这个表达式阻塞了主线程delay(3000L)//阻塞主线程防止过快退出}println("\n示例结束")}

可以看到,runBlocking里使用了delay来延迟。用了runBlocking的主线程会一直阻塞直到runBlocking内部的协程执行完毕。 也就是runBlocking{ delay }实现了阻塞的效果。

我们也可以用runBlocking来包装主函数。

importkotlinx.coroutines.\*funmain()=runBlocking{delay(100)// 在这里可以用delay了GlobalScope.launch{delay(100)println("Fisher")}print("Rust ")delay(3000)}

runBlocking<Unit>中的<Unit>目前可以省略。

runBlocking也可用在测试中

// 引入junitdependencies{implementation("junit:junit:4.13.1")}

单元测试

使用@Test设置测试

importorg.junit.Testimportkotlinx.coroutines.\*classC3Test{@Test funtest1()=runBlocking{println("junit测试开始 ${System.currentTimeMillis()}")delay(1234)println("junit测试结束 ${System.currentTimeMillis()}")}}

运行结果

junit测试开始1632401800686junit测试结束1632401801928

IDEA可能会提示no tasks available。需要把测试选项改为IDEA,如下图。

更改设置

2. 等待

有时候需要等待协程执行完毕。可以用join()方法。这个方法会暂停当前的协程,直到执行完毕。需要用main() = runBlocking

importkotlinx.coroutines.\*funmain()=runBlocking{println("测试等待")val job1=GlobalScope.launch{println("job1 start")delay(300)println("job1 done")}val job2=GlobalScope.launch{println("job2 start")delay(800)println("job2 done")}job2.join()job1.join()// 等待println("测试结束")}

运行log

测试等待 job1 start job2 start job1 done job2 done 测试结束
3. 结构化的并发

GlobalScope.launch时,会创建一个顶层协程。它不使用主线程。新创的协程虽然轻量,但仍会消耗一些内存资源。如果忘记保持对新启动的协程的引用,它还会继续运行。

我们可以在代码中使用结构化并发。

示例中,我们使用runBlocking协程构建器将main函数转换为协程。在里面(作用域)启动的协程不需显式使用join

观察下面的例子:

importkotlinx.coroutines.\*funmain()=runBlocking<Unit>{println("主线程id ${Thread.currentThread().id}")launch{// 在 runBlocking 作用域中启动一个新协程1println("协程1所在线程id ${Thread.currentThread().id}")delay(300)println("协程1执行完毕")}launch{// 在 runBlocking 作用域中启动一个新协程2println("协程2所在线程id ${Thread.currentThread().id}")delay(500)println("协程2执行完毕")}println("主线程执行完毕")}

运行log

主线程id1主线程执行完毕 协程1所在线程id1协程2所在线程id1协程1执行完毕 协程2执行完毕

可以看到,不用像之前那样调用Thread.sleep或者delay让主线程等待一段时间,防止虚拟机退出。

程序会等待它所有的协程执行完毕,然后真正退出。

4. 作用域构建器

使用coroutineScope构建器声明自己的作用域。它会创建一个协程作用域,并且会等待所有已启动子协程执行完毕。

runBlockingcoroutineScope看起来类似,因为它们都会等待其协程体以及所有子协程结束。主要区别在于:

*runBlocking方法会阻塞当前线程来等待,是常规函数

*coroutineScope只是挂起,会释放底层线程用于其他用途,是挂起函数

下面这个示例展示了作用域构建器的特点。main是一个作用域。

importkotlinx.coroutines.\*funmain()=runBlocking{// this: CoroutineScopelaunch{delay(200L)println("协程1 t${Thread.currentThread().id}")}coroutineScope{// 创建一个协程作用域launch{delay(500L)println("内部协程2-1 t${Thread.currentThread().id}")}delay(100L)println("协程2 t${Thread.currentThread().id}")}println("主任务完毕")}

运行log

协程2t1 协程1t1 内部协程2-1t1 主任务完毕
5. 提取函数重构

launch { …… }内部的代码块提取到独立的函数中。提取出来的函数需要suspend修饰符,它是挂起函数

importkotlinx.coroutines.delayimportkotlinx.coroutines.launchimportkotlinx.coroutines.runBlocking funmain()=runBlocking<Unit>{launch{r1()}println("DONE")}// 挂起函数suspend funr1(){delay(300)println("提取出来的函数")}

log

DONE提取出来的函数
6. 协程是轻量的

我们前面也试过,创建非常多的协程,程序运行OK。

下面的代码可以输出很多的点

importkotlinx.coroutines.\*funmain()=runBlocking{for(tin1..10000){launch{delay(t \*500L)print(".")}}}
7. 全局协程像守护线程

如果进程中只剩下了守护线程,那么虚拟机会退出。 前文那个的例子,其实也能看到,字符没打印完程序就结束了。

GlobalScope中启动的活动协程并不会使进程保活。它们就像守护线程。

再举一个例子

importkotlinx.coroutines.\*funmain()=runBlocking{GlobalScope.launch{for(iin1..1000000){delay(200)println("协程执行: $i")}}delay(1000)println("Bye~")}

log

协程执行:1协程执行:2协程执行:3协程执行:4Bye~

最后分享一份

【腾讯技术团队出品】Android零基础入门到精通,Android Studio安装教程+全套安卓基础教程

Android编程入门教程

Java语言基础从入门到熟悉

Kotlin语言基础从入门到熟悉

Android 技术栈从入门到熟悉

Android Jetpack 全家桶全面学习

对于新手来说可能安装Android Studio存在一定困难你可以看着以下视频,一步步的跟着学习安装运行

Android Studio 安装教程

有了Java阶段的学习,这一阶段建议以视频学习为主辅以图书查漏补缺。如果以图书为主,可以根据图书讲解敲代码,辅以教学视频查漏补缺。遇到问题可以去百度,入门的问题一般会有很多人遇到,并且给出比较好的解答。

需要掌握基本知识点,比如四大组件如何使用、如何创建Service、如何进行布局、简单的自定义View、动画、网络通信等常见技术。

全套零基础教程已经为你们准备好了,需要的可以添加下方二维码免费领取

全套安卓基础教程





版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 12:51:41

Android入门教程 | Fragment 基础概念

什么是Fragment&#xff1f; Fragment&#xff0c;直译为“碎片”&#xff0c;“片段”。 Fragment 表示 FragmentActivity 中的行为或界面的一部分。可以在一个 Activity 中组合多个片段&#xff0c;从而构建多窗格界面&#xff0c;并在多个 Activity 中重复使用某个片段。可…

作者头像 李华
网站建设 2026/8/27 12:49:32

Android之Bmob移动后端云服务器

PS&#xff1a;一般情况下&#xff0c;我们在写android程序的时候&#xff0c;想要实现登录注册功能&#xff0c;可以选择自己用servlet作为服务端来实现过滤没有注册过的用户&#xff0c;但是太麻烦&#xff0c;而且不是随时都可以用的。这里介绍一个移动后端云服务器平台bmob…

作者头像 李华
网站建设 2026/8/27 12:49:18

纳米AI word导出总崩?安卓用户的痛,AI导出鸭终于治好了

纳米AI word导出总崩&#xff1f;安卓用户的痛&#xff0c;AI导出鸭终于治好了看似简单的复制粘贴&#xff0c;背后是 LaTeX 到 OMML 的底层映射、Mermaid 到矢量图的实时编译&#xff0c;以及安卓系统资源调度权限的多重博弈。让 AI 导出回归优雅&#xff0c;远非一键那么表面…

作者头像 李华
网站建设 2026/8/27 12:48:54

ChatGPT生成的表格怎么导出?安卓用户的“格式避难”实录

ChatGPT生成的表格怎么导出&#xff1f;安卓用户的“格式避难”实录 你有没有过这样的经历&#xff1f;在手机上用DeepSeek或ChatGPT生成了一张数据完美的表格&#xff0c;兴冲冲地复制到WPS或Excel里&#xff0c;结果—— 数字变成了科学计数法&#xff0c;日期变成了五位数序…

作者头像 李华
网站建设 2026/8/27 12:47:18

浅谈 Android Handler

handler是什么&#xff1f; handler是Android提供用来更新UI的一套消息机制&#xff0c;也是一套消息处理的机制&#xff08;发送和处理消息&#xff09; handler原理 handler负责消息发送&#xff0c;looper负责接收handler发送过来的消息&#xff0c;并把消息发送给handle…

作者头像 李华