Kotlin 协程与挂起函数Coroutines suspend入门到实战Kotlin 协程是 Android 和后端 Kotlin 开发里最核心的异步方案之一。很多人第一次学协程时会卡在几个地方suspend到底是什么协程是不是线程为什么不会阻塞launch、async、withContext有什么区别Android 项目到底该怎么用这篇教程按**“从能看懂 → 能写 → 能实战”**的方式讲。一、为什么需要协程先看传统代码fundownloadData(){Thread{Thread.sleep(3000)runOnUiThread{textView.text下载完成}}.start()}问题回调嵌套线程管理麻烦容易内存泄漏异步代码像地狱协程的写法lifecycleScope.launch{delay(3000)textView.text下载完成}是不是像同步代码但它实际上是异步的。这就是协程最大的意义用同步代码的写法完成异步操作。二、什么是协程Coroutine协程可以理解为“轻量级线程”但它不是线程。线程 vs 协程对比线程协程系统级是否创建成本高极低切换成本高很低数量少可以很多阻塞容易默认非阻塞依赖关系线程包含协程协程运行在线程上比如repeat(100000){launch{delay(1000)}}10万个协程都没问题。但10万个线程直接炸。三、挂起函数 suspend 到底是什么这是最关键的地方。1. suspend 不是异步很多人误解suspendfuntest()≠自动开线程≠自动异步suspend的真正含义这个函数可以暂停而不阻塞线程。2. 什么叫挂起suspendfunloadData(){delay(3000)println(完成)}这里delay(3000)会暂停当前协程释放线程3秒后恢复注意线程没有被卡死。3. Thread.sleep 和 delay 的区别// Thread.sleepThread.sleep(3000)// 特点阻塞线程什么都干不了// delaydelay(3000)// 特点只暂停协程不阻塞线程直观理解假设线程 厨房协程 厨师Thread.sleepdelay厨师睡觉厨师说“3秒后叫我”厨房也废了厨房还能给别人做饭这就是协程高性能的核心。四、协程的基本使用先添加依赖implementationorg.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3五、launch启动协程GlobalScope.launch{delay(1000)println(协程执行)}launch 特点说明启动协程无返回值异步执行类似new Thread()但更轻量六、runBlocking学习阶段使用funmain()runBlocking{launch{delay(1000)println(协程)}println(开始)}输出开始 协程runBlocking是什么作用阻塞当前线程直到内部协程结束适合学习、测试不适合Android 主线程七、async 与 await需要返回值时runBlocking{valresultasync{delay(2000)请求成功}println(result.await())}async 特点说明有返回值返回Deferredawait()等待结果八、协程调度器 Dispatcher协程运行在哪个线程由Dispatcher决定。九、常见 Dispatcher1. Main主线程Dispatchers.Main用于更新UI2. IOIO线程池Dispatchers.IO用于网络、数据库、文件3. DefaultCPU密集型Dispatchers.Default用于排序、JSON解析、大计算十、withContext线程切换最常用。lifecycleScope.launch{valresultwithContext(Dispatchers.IO){// 网络请求服务器数据}textView.textresult}执行流程主线程launch ↓ 切换IO线程withContext(IO) ↓ 执行完成 ↓ 自动回主线程十一、协程作用域 CoroutineScope协程必须运行在作用域里。十二、GlobalScope 为什么不推荐GlobalScope.launch{}问题生命周期不可控容易内存泄漏Activity销毁还在运行所以Android开发基本不用。十三、Android 正确写法lifecycleScope// ActivitylifecycleScope.launch{}// FragmentviewLifecycleOwner.lifecycleScope.launch{}特点页面销毁自动取消协程十四、ViewModel 中使用classMainViewModel:ViewModel(){funload(){viewModelScope.launch{valdatawithContext(Dispatchers.IO){api.getData()}}}}这是Android 官方推荐方案。十五、协程取消机制valjoblaunch{repeat(100){delay(1000)println(it)}}job.cancel()为什么协程能取消因为delay()会检查取消状态。十六、Job每个协程都有 Job。valjoblaunch{}作用cancel、join、管理生命周期十七、join()等待协程结束valjoblaunch{delay(2000)}job.join()println(结束)十八、异常处理try-catchlaunch{try{valdataapi.load()}catch(e:Exception){// 处理异常}}十九、SupervisorJob普通情况下一个子协程崩了全部取消。SupervisorJobvalscopeCoroutineScope(SupervisorJob()Dispatchers.Main)特点一个失败不影响其他协程。Android 很常用。二十、协程常见面试题1. suspend 和 coroutineScope 区别suspend— 只是说明函数可挂起coroutineScope— 会创建协程作用域2. launch 和 async 区别launchasync无返回值有返回值返回 Job返回 Deferred3. delay 为什么不卡线程因为它会挂起协程不阻塞线程4. 协程是不是线程不是。协程运行在线程上。二十一、Android 实战案例场景1网络请求viewModelScope.launch{try{valdatawithContext(Dispatchers.IO){api.getUser()}tvName.textdata.name}catch(e:Exception){toast(请求失败)}}场景2并发请求viewModelScope.launch{valuserTaskasync(Dispatchers.IO){api.getUser()}valvideoTaskasync(Dispatchers.IO){api.getVideo()}valuseruserTask.await()valvideovideoTask.await()}优势两个请求同时执行。场景3倒计时lifecycleScope.launch{for(iin10downTo0){tv.text$idelay(1000)}}二十二、Flow 与协程关系很多人混淆。协程Flow解决一个异步任务解决连续的数据流比如搜索输入、股票数据、聊天消息、Room数据库监听简单例子flow{emit(1)delay(1000)emit(2)}二十三、协程学习路线推荐建议顺序launchsuspenddelayasync/awaitDispatcherwithContextlifecycleScopeviewModelScopeJobFlow二十四、协程核心理解最重要suspend 可以暂停协程但不会阻塞线程你就已经超过很多只会背API的人了。二十五、实际开发最佳实践1. 不要用 GlobalScope改用viewModelScopelifecycleScope2. IO任务放 Dispatchers.IOwithContext(Dispatchers.IO)3. UI更新必须 Main线程Dispatchers.Main4. Repository 不要持有 Scope错误classRepository{valscopeCoroutineScope(...)}容易泄漏。二十六、完整 Android MVVM 示例ViewModelclassUserViewModel:ViewModel(){valuserLiveDataMutableLiveDataUser()funloadUser(){viewModelScope.launch{valuserwithContext(Dispatchers.IO){api.getUser()}userLiveData.valueuser}}}ActivityviewModel.userLiveData.observe(this){tvName.textit.name}二十七、总结核心作用suspend挂起函数launch启动协程async异步返回值delay非阻塞等待withContext切线程Dispatcher指定线程viewModelScopeAndroid推荐作用域Flow数据流最后一段真正理解协程很多人学协程只会背launchasyncwithContext但真正重要的是协程的本质不是开线程。而是用极低成本管理大量异步任务。