Android-kotlin协程学习总结

Kotlin协程实战对话

真题1:协程与线程的本质区别是什么?为什么说协程是轻量级的?​

面试官​:
“我看你项目中用协程替代了线程池,能说说协程和线程的核心区别吗?为什么协程更适合高并发?”

候选人​:
“协程和线程的区别有点像‘快递员’和‘卡车’的关系。线程是操作系统直接管理的‘大卡车’,每辆卡车得自己带一整个货箱(1MB的栈内存),启动和换路线得经过调度中心(内核态),成本高还慢。而协程更像是快递员,他们骑电动车(用户态调度),一辆卡车能装几千个快递员,换任务时只需要记下当前位置,轻装上阵,内存开销只有几十KB。

比如我们做电商秒杀,10万用户同时抢购。如果用线程池,开500个线程就得吃掉500MB内存,线程切换还得排队等调度,CPU都忙不过来。换成协程,一个线程就能跑几万个请求,内存省了90%,QPS直接翻倍——这就像用电动车送快递,不堵车还省油。”


真题2:GlobalScope为什么会导致内存泄漏?如何正确使用作用域?​

面试官​:
“你们项目里把GlobalScope全换成了lifecycleScope,是踩过坑吧?”

候选人​:
“没错!之前做视频弹幕功能时,用GlobalScope启动了一个无限循环的弹幕请求。结果用户退出了页面,协程还在后台疯狂拉数据,Fragment像僵尸一样赖在内存里,直接导致OOM崩溃。后来发现GlobalScope是‘长生不老’的,它的生命周期和整个App绑定,根本不管Activity的死活。

现在我们用lifecycleScope,相当于给协程装了‘智能开关’。Activity销毁时,自动触发onDestroy里的取消逻辑。就像给电器装了个漏电保护器——页面一关,所有后台任务立马断电,内存泄漏风险直接清零。

比如在ViewModel里这么写:

viewModelScope.launch { val data = withContext(Dispatchers.IO) { fetchData() } _liveData.value = data  //自动绑定到ViewModel生命周期
}

就算用户疯狂滑动页面,旧的请求也会被及时取消,再也不用担心后台跑‘幽灵任务’了。”


真题3:如何处理协程中的并发任务?async和launch有什么区别?​

面试官​:
“如果要同时调三个接口,等结果全到了再更新UI,用协程怎么搞?如果有一个接口挂了怎么办?”

候选人​:
“这得请出‘协程三剑客’——asyncawaitcoroutineScope。比如用户主页需要同时拉取用户信息、订单列表和消息通知,可以这么写:

lifecycleScope.launch {try {val (user, orders, messages) = coroutineScope {val userDeferred = async { api.getUser() }      // 并行启动val ordersDeferred = async { api.getOrders() }val messagesDeferred = async { api.getMessages() }Triple(userDeferred.await(), ordersDeferred.await(), messagesDeferred.await())}updateUI(user, orders, messages)  // 三个结果都到了才更新} catch (e: Exception) {showErrorToast("有一个接口挂了:${e.message}")  // 任一失败都会跳到这里}
}

这里的关键是coroutineScope会‘一损俱损’——只要有一个子协程抛异常,整个作用域里的任务全取消。而async和launch的核心区别在于‘带不带回执’——async返回Deferred对象(类似快递单号),需要用await获取结果,适合需要聚合数据的场景;launch则像‘寄平邮’,适合日志上报等无需返回值的任务


真题4:协程的挂起函数底层是如何实现的?​

面试官​:
“你说delay(1000)不阻塞线程,那协程怎么做到‘暂停而不卡死’的?”

候选人​:
“这得看Kotlin编译器的‘魔法’——CPS变换状态机。比如这个挂起函数:

suspend fun fetchData(): String {delay(1000)          // 挂起点1return "Data"         // 挂起点2
}

编译后会变成‘代码乐高’:

Object fetchData(Continuation $completion) {switch (label) {case 0: delay(1000, $completion);  // 记录位置1label = 1;return COROUTINE_SUSPENDED; // 挂起case 1: return "Data";             // 从位置1恢复}
}

Continuation就像书签,记录执行到哪里了。当delay触发时,协程把书签交给线程:‘你先去忙别的,1秒后喊我’。这时候线程腾出手来处理UI点击或者别的请求,完全不卡顿。时间一到,线程通过resume()把书签插回去,继续执行——整个过程像接力赛,而不是傻站着等。”


真题5:如何用协程优化RecyclerView的图片加载?​

面试官​:
“列表快速滑动时图片加载卡顿,你们怎么用协程解决的?”

候选人​:
“传统方案在onBindViewHolder里直接开线程,用户一滑到底,几百个请求把线程池挤爆。我们给每个Item绑定独立的Job,滑动时自动取消不可见的请求:

class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {private var loadJob: Job? = nullfun bind(url: String) {loadJob?.cancel()  // 先取消之前的任务loadJob = lifecycleScope.launch {val bitmap = withContext(Dispatchers.IO) { loadImage(url)  // 耗时操作}if (isActive) {     // 检查是否已被取消itemView.image.setImageBitmap(bitmap)}}}fun unbind() {loadJob?.cancel()  // 视图滚出屏幕时取消}
}

对比Glide,这套方案更灵活——比如先加载缩略图,再用协程组合高清图加载,还能统一处理异常。之前列表滑动FPS只有30,优化后稳定60,内存波动减少70%。”

面试追问扩展

面试官​:

“协程和线程的本质区别是什么?为什么说协程更适合高并发场景?”

候选人​:

“您可以想象协程就像快递站里的一群快递员,而线程是送货的大卡车。卡车每次出发都要装货、申请路线、排队等调度,一趟只能送一个包裹,成本高还慢。而快递员们共用几辆电动车,一个卡车能塞下几百个快递员,每个人记下自己的送货路线,到了路口灵活切换——协程就这么干的。它不用等操作系统调度,自己管理任务切换,一个线程能跑几万个协程,内存开销只有几十KB。比如我们做秒杀活动,10万人同时抢购,用线程池开500个线程内存就爆了,但换成协程,一个线程轻松扛住,还能自动取消没必要的请求,这就是轻量级的威力。”


面试官​:

“听说GlobalScope容易导致内存泄漏,你们项目里是怎么解决的?”

候选人​:

“这真是血泪教训!之前做视频弹幕功能,用GlobalScope启动了一个无限循环的弹幕请求,结果用户退出页面后,协程还在后台疯狂拉数据,Fragment像‘僵尸’一样赖在内存里,最后直接OOM崩溃。后来才明白,GlobalScope是‘长生不老’的,它的生命周期和整个App绑定,根本不管Activity的死活。现在我们全员改用lifecycleScope——相当于给协程装了智能开关,页面销毁时自动断电。比如在Fragment里发起网络请求,只要用lifecycleScope.launch,用户一返回,请求立刻取消,再也不会出现后台偷偷耗流量的问题了。”


面试官​:

“用户快速滑动商品列表,每个Item都要加载图片,用协程怎么防止卡顿和错乱?”

候选人​:

“这个问题我们优化了三个月!首先,​给每个图片加载任务打标签。比如商品ID是123,加载完成后对比ImageView当前绑定的ID,如果不一样就直接丢弃,防止图片错位。其次,​用协程作用域控制生命周期。在RecyclerView的ViewHolder里,每次绑定新数据时,先取消前一个协程任务,像这样——”

候选人用手比划着空气代码:
“在onBindViewHolder里启动协程前,先检查job是否活跃,如果还在跑就立刻cancel。最后,​给IO操作加限流。比如用Dispatchers.IO的limitedParallelism限制同时加载的图片数,避免100张图同时开线程,线程池直接被打爆。现在我们的列表滑动FPS稳定在60帧,内存占用降了60%。”


面试官​:

“如果协程嵌套了三层异步任务,突然父协程被取消,会发生什么?”

候选人​:

“这就好比拆炸弹时剪错了线——子协程会连锁爆炸!结构化并发的核心思想就是‘要活一起活,要死一起死’。比如父协程负责订单支付,内部启动了子协程A查库存、子协程B扣积分。如果用户突然退出了页面,父协程取消,A和B会立刻收到取消信号,哪怕B已经完成了90%,也会立刻回滚。这虽然残酷,但保证了资源不会部分提交(比如积分扣了但库存没锁)。如果想让某个子协程‘苟活’,比如日志上报任务,可以用SupervisorJob把它包起来,这样即使父协程挂了,它还能在后台默默执行完。”

Android学习总结之Kotlin 协程_android kotlin协程-CSDN博客https://blog.csdn.net/2301_80329517/article/details/146909197Android学习总结之协程对比优缺点(协程一)_android 协程和线程-CSDN博客https://blog.csdn.net/2301_80329517/article/details/147256220

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/82823.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uni-app学习笔记十四-vue3中emit的使用

在组件传值中&#xff0c;无论是props还是slot都是单向数据流&#xff0c;父组件向子组件传值&#xff0c;子组件不能直接对父组件传过来的值进行重新赋值。 下面学习子组件向父组件传值的工具--emit。 在子组件emit设置传递的函数名和值 <template><view>子组件…

Java设计模式从基础到实际运用

第一部分&#xff1a;设计模式基础 1. 设计模式概述 设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的代码设计经验的总结&#xff0c;它描述了在软件设计过程中一些不断重复出现的问题以及该问题的解决方案。设计模式是在特定环境下解决软件设计问题…

鸿蒙OSUniApp 制作自定义的进度条组件#三方框架 #Uniapp

使用 UniApp 制作自定义的进度条组件 在移动应用开发中&#xff0c;进度条是非常常见的 UI 组件&#xff0c;无论是文件上传、下载、任务进度还是表单填写反馈&#xff0c;进度条都能为用户提供直观的进度提示。虽然 UniApp 提供了一些基础的进度条能力&#xff0c;但在实际项…

Python爬虫实战:研究Beautiful Soup框架相关技术

1. 引言 1.1 研究背景与意义 随着互联网的快速发展,网络上的数据量呈爆炸式增长。如何从海量的网页数据中高效提取有价值的信息,成为信息科学领域的重要研究课题。网络爬虫作为一种自动获取网页内容的技术,能够按照预设规则遍历互联网并采集数据,为信息检索、舆情分析、商…

【Tips】关于PCI和PCIe的配置空间差异和io/memory io读写

最近在看同事2023年讲的PCI基础课&#xff0c;感觉确实是豁然开朗了&#xff0c;赞美同事。 PCIe实际上是PCI的扩展&#xff08;extended&#xff09;&#xff0c;PCIe设备相当于是迭代升级产品。 而PCIe的配置空间基于PCI原有的0xFF&#xff08;256字节&#xff09;配置空间…

桂花网体育运动监测方案:开启幼儿园运动健康管理新篇章

在幼儿教育领域&#xff0c;运动能力的培养与健康监测始终是备受关注的核心环节。随着科技的飞速发展&#xff0c;如何科学、有效地监测幼儿的运动状态&#xff0c;成为了幼儿园教育者面临的一大挑战。桂花网体育运动监测方案凭借其高效、精准、智能化的特性&#xff0c;为幼儿…

Perforce P4产品简介:无限扩展+全球协作+安全管控+工具集成(附下载)

本产品简介由Perforce中国授权合作伙伴——龙智编辑整理&#xff0c;旨在带您快速了解Perforce P4版本控制系统的强大之处。 世界级无限可扩展的版本控制系统 Perforce P4&#xff08;原Helix Core&#xff09;是业界领先的版本控制平台&#xff0c;备受19家全球Top20 AAA级游…

pikachu靶场通关笔记08 XSS关卡04-DOM型XSS

目录 一、XSS原理 二、DOM型XSS 三、源码分析 1、进入靶场 2、XSS探测 3、源码分析 四、渗透实战 1、Payload1 2、Payload2 3、Payload3 本系列为通过《pikachu靶场通关笔记》的XSS关卡(共10关&#xff09;渗透集合&#xff0c;通过对XSS关卡源码的代码审计找到XSS风…

安全访问 std::tuple 的容错方法及气象领域应用

安全访问 std::tuple 的容错方法及气象领域应用 1. std::tuple 安全访问的核心问题 1.1 元组结构性问题&#xff08;编译时错误&#xff09; 当元组元素数量为空时&#xff08;std::tuple<>&#xff09;&#xff0c;任何访问元素的尝试都会导致编译错误​&#xff1a;…

Webug4.0靶场通关笔记03- 第3关SQL注入之时间盲注(手注法+脚本法 两种方法)

目录 一、源码分析 1.分析闭合 2.分析输出 &#xff08;1&#xff09;查询成功 &#xff08;2&#xff09;查询失败 &#xff08;3&#xff09;SQL语句执行报错 二、第03关 延时注入 1.打开靶场 2.SQL手注 &#xff08;1&#xff09;盲注分析 &#xff08;2&#xf…

【大模型学习网络互联】Memory-Mapped I/O MMIO语义与MEM语义

MMIO语义和MEM语义的区别 嗯&#xff0c;用户要求更详细地区分MMIO和MEM语义&#xff0c;看来之前的中文对比虽然系统但还不够深入。用户可能是嵌入式开发者或OS内核学习者&#xff0c;需要从硬件行为层面理解差异。 用户连续追问MMIO相关概念&#xff0c;说明ta在接触底层开发…

如何在使用kickstart安装物理机操作系统的过程中核对服务器的SN

原因 在使用kickstart对物理机进行重装的时候&#xff0c;由于自动化配置&#xff0c;挂载镜像重启之后就会自动化开始安装部署&#xff0c;不够安全&#xff0c;万一选错服务器没有办法回退。因此可以在kickstart的ks配置文件中新增服务器SN的校验&#xff0c;当校验不通过的…

spring4第4课-ioc控制反转-详解如何注入参数

坚持住&#xff0c;第四天&#xff0c;继续学习spring4.详解如何注入参数 先总结&#xff0c;主要有如下6种&#xff1a; 1&#xff0c;基本类型值&#xff1b; 2&#xff0c;注入 bean&#xff1b; 3&#xff0c;内部 bean&#xff1b; 4&#xff0c;null 值&#xff1b; 5&…

cf2067A

原题链接&#xff1a;https://codeforces.com/contest/2067/problem/A 题目背景&#xff1a; 给定x,y&#xff0c;判读是否存在 n 满足S(n) x&#xff0c;S(n 1) y。定义 S(a) 等于 a 的十进制位数之和。 思路&#xff1a; 不难发现一般 n 和 n 1 的位数之和相差为 1&…

微信小程序获取手机号

详细代码 <t-button size"large" theme"primary" variant"outline" data-type"hasCancelBtn" bind:tap"showDialog" block style"display: none;">开放能力按钮 </t-button> <t-dialog id"t-…

AI重构SEO关键词精准定位

内容概要 随着AI技术深度渗透数字营销领域&#xff0c;传统SEO关键词定位模式正经历系统性重构。基于自然语言处理&#xff08;NLP&#xff09;的智能语义分析引擎&#xff0c;可突破传统关键词工具的局限性&#xff0c;通过解析长尾搜索词中的隐含意图与语境关联&#xff0c;…

四足机器人环境监测系统相关问题

一、在设计四足机器人监测与跟踪系统整体架构时&#xff0c;你主要考虑了哪些因素&#xff1f;为什么这样设计以确保系统的高效性与稳定性&#xff1f; 在设计四足机器人监测与跟踪系统整体架构时&#xff0c;主要考虑了传感器兼容性与通信效率、多任务并发处理能力、实时数据…

uniapp 开发安卓app 微信授权获取昵称 头像登录

在manifest.json中配置appid 以及appsecret uni.login({provider: weixin,success: function (loginRes) {console.log(loginRes.authResult);// 获取用户信息uni.getUserInfo({provider: weixin,success: function (infoRes) {console.log(用户昵称为&#xff1a; infoRes.u…

MySQL8.4组复制

https://dev.mysql.com/doc/refman/8.4/en/group-replication.html 1 什么是组复制 组复制主要解决了传统异步复制主机宕机时可能造成主从节点数据不一致问题MySQL Group Replication&#xff0c;简称MGR将原有的gtid复制功能进行可增强&#xff0c;支持单主模式和多主模式组复…

Python后端开发实战:从0到1搭建高可用API服务

引言 Python凭借其简洁的语法和丰富的生态(如Django、Flask、FastAPI等框架),已成为后端开发的主流语言之一。本文将结合一个真实电商API项目,分享从架构设计到部署上线的完整流程,并总结开发过程中常见的坑与最佳实践。 一、实战案例:电商API开发流程 1.1 技术选型 框…