源码解读笔记:协程的 ViewModel.viewModelScope和LifecycleOwner.lifecycleScope
分析下ViewModel.viewModelScope
public val ViewModel.viewModelScope: CoroutineScopeget() {val scope: CoroutineScope? = this.getTag(JOB_KEY)if (scope != null) {return scope}return setTagIfAbsent(JOB_KEY,CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))}internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {override val coroutineContext: CoroutineContext = contextoverride fun close() {coroutineContext.cancel()}
}
1. ViewModel.viewModelScope:
这是一个公共的只读属性,用于获取或创建与 ViewModel 关联的 CoroutineScope。
get 函数用于计算属性值。它首先尝试从 ViewModel 的 tag(存储在 this.getTag(JOB_KEY) 中)获取已存在的 CoroutineScope。
如果找到了已存在的 CoroutineScope(scope != null),则直接返回它。
如果没有找到,它将创建一个新的 CloseableCoroutineScope 并将其设置为 ViewModel 的 tag,同时返回新创建的 CoroutineScope。
创建的 CoroutineScope 由一个 SupervisorJob 和 Dispatchers.Main.immediate 组成,这表示协程将在主线程上运行,并且具有超时监督策略。
2. CloseableCoroutineScope:
这是一个内部类,实现了 Closeable 和 CoroutineScope 接口。
实现了 CoroutineScope.coroutineContext 属性,它返回给定的 CoroutineContext 参数,通常是一个组合了 Job 和 Dispatcher 的上下文。
实现了 Closeable.close() 方法,当调用 close() 时,它会取消关联的 CoroutineContext,这通常意味着取消所有正在运行的协程。
总结一下,这段代码的主要目的是为 ViewModel 提供一个可管理的协程作用域,这个作用域与 ViewModel 的生命周期绑定,并且可以在需要时安全地取消所有协程。
CloseableCoroutineScope 确保了协程的生命周期管理,当不再需要时可以被关闭,从而避免资源泄漏。Dispatchers.Main.immediate 确保所有在此作用域内启动的协程都在主线程上执行,这对于更新 UI 是必要的。
3. 其中的SupervisorJob()
SupervisorJob 是 Kotlin 协程库中的一个类,它是 Job 的一个子类,主要用于管理协程的生命周期。
SupervisorJob 的主要特点是它采用了所谓的“非传播”异常策略,这意味着如果在其子协程中发生异常,SupervisorJob 不会因为这些异常而自动取消自身或其他子协程。
这种设计是为了防止一个子任务的错误导致整个工作树的崩溃,使得其他任务有机会完成或者独立处理错误。
使用 SupervisorJob 的场景通常包括:
- 错误隔离:如果你希望一个子任务的失败不会影响其他子任务,可以使用 SupervisorJob 创建这些子任务的父级作用域。
- 独立性:在多个任务之间需要保持独立性,即使其中一个失败,其他任务也应该继续运行。
- 资源清理:在某些情况下,你可能希望即使有子任务失败,仍然能够执行清理操作,如关闭文件流或网络连接。
在上述代码中,SupervisorJob() 被用来创建一个 CloseableCoroutineScope 的上下文,这意味着在这个作用域内启动的所有协程都将受到 SupervisorJob 的管理,它们会在主线程上运行,并且即使其中一个协程由于异常而终止,其他协程仍将继续执行。
这对于 ViewModel 来说是一个很好的选择,因为它允许 ViewModel 中的不同任务独立处理错误,而不是整体崩溃。
分析下LifecycleOwner.lifecycleScope:
public val LifecycleOwner.lifecycleScope: LifecycleCoroutineScopeget() = lifecycle.coroutineScope
定义了一个扩展属性 coroutineScope,适用于 Lifecycle 类型的对象。这个属性返回一个 LifecycleCoroutineScope 对象。
public val Lifecycle.coroutineScope: LifecycleCoroutineScopeget() {while (true) {val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?if (existing != null) {return existing}val newScope = LifecycleCoroutineScopeImpl(this,SupervisorJob() + Dispatchers.Main.immediate)if (mInternalScopeRef.compareAndSet(null, newScope)) {newScope.register()return newScope}}}
- 使用无限循环来确保在多线程环境下正确获取或创建 LifecycleCoroutineScope。
- 检查现有作用域:从 mInternalScopeRef 中获取现有的 LifecycleCoroutineScopeImpl 实例。 如果存在现有实例,则直接返回该实例。
- 否则,创建新作用域:创建一个新的 LifecycleCoroutineScopeImpl 实例。
- this 表示当前的 Lifecycle 对象。
- SupervisorJob() 创建一个监督者作业,允许子作业独立于父作业失败。
- Dispatchers.Main.immediate 确保协程在主线程上立即执行
- 原子性设置:使用 compareAndSet 方法尝试原子地将 mInternalScopeRef 设置为新的 newScope。
- 如果设置成功,则调用 newScope.register() 注册新作用域,并返回新作用域。
- 如果设置失败(即已经有其他线程设置了 mInternalScopeRef),则继续循环,重新检查现有作用域。
总结
- 目的:这个属性 coroutineScope 提供了一个与 Lifecycle 绑定的协程作用域,确保在生命周期管理下安全地执行协程。
- 线程安全:通过无限循环和 compareAndSet 方法,确保在多线程环境下正确创建和获取 LifecycleCoroutineScope。
- 作用域配置:使用 SupervisorJob 和 Dispatchers.Main.immediate 配置协程作用域,确保协程在主线程上立即执行,并且子协程可以独立于父协程失败。
使用场景 - 生命周期绑定:在 Fragment 或 Activity 中使用 lifecycleScope 可以确保协程在组件的生命周期内安全地执行,避免内存泄漏和资源浪费。
- 主线程操作:适用于需要在主线程上执行的 UI 相关操作,如更新界面、处理用户交互等
相关文章:
源码解读笔记:协程的 ViewModel.viewModelScope和LifecycleOwner.lifecycleScope
分析下ViewModel.viewModelScope public val ViewModel.viewModelScope: CoroutineScopeget() {val scope: CoroutineScope? this.getTag(JOB_KEY)if (scope ! null) {return scope}return setTagIfAbsent(JOB_KEY,CloseableCoroutineScope(SupervisorJob() Dispatchers.Ma…...
11.27周三F34-Day8打卡
文章目录 1. 学习让我感觉很棒。(什么关系?动作 or 描述?主语部分是?)解析答案:【解析答案分析】【对比分析】【拓展内容】2. 她忽然想起来钥匙放另一个包里了。解析答案:【拓展内容】3. 她来不来都没关系。(该由什么引导?这句话又属于什么关系,动作 or 描述?)解析答案…...
XG(S)-PON原理
前言 近年来,随着全球范围内接入市场的飞快发展以及全业务运营的快速开展,已有的PON技术标准在带宽需求、业务支撑能力以及接入节点设备和配套设备的性能提升等方面都面临新的升级需求XG(S)-PON(10G GPON)是在已有GPON技术标准上演进的增强下一代GPON技…...
C语言实例之9斐波那契数列实现
1. 斐波那契数列简介 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多・斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为 “兔子数列”。 它的特点是从第三…...
YOLO系列论文综述(从YOLOv1到YOLOv11)【第1篇:概述物体检测算法发展史、YOLO应用领域、评价指标和NMS】
目录 1 前言2 YOLO在不同领域的应用3 物体检测指标和NMS3.1 mAP和IOU3.2 mAP计算流程3.2.1 VOC 数据集3.2.2 微软 COCO 数据集 3.3 NMS 1 前言 最近在做目标检测模型相关的优化,重新看了一些新的论文,发现了几篇写得比较好的YOLO系列论文综述࿰…...
数据结构--Map和Set
目录 一.二叉搜索树1.1 概念1.2 二叉搜索树的简单实现 二.Map2.1 概念2.2 Map常用方法2.3 Map使用注意点2.4 TreeMap和HashMap的区别2.5 HashMap底层知识点 三.Set3.1 概念3.2 Set常用方法3.3 Set使用注意点3.4 TreeSet与HashSet的区别 四.哈希表4.1 概念4.2 哈希冲突与避免4.3…...
计算机操作系统——进程控制(Linux)
进程控制 进程创建fork()函数fork() 的基本功能fork() 的基本语法fork() 的工作原理fork() 的典型使用示例fork() 的常见问题fork() 和 exec() 结合使用总结 进程终止与$进程终止的本质进程终止的情况正常退出(Exit)由于信号终止非…...
【前端】ES6基础
1.开发工具 vscode地址 :https://code.visualstudio.com/download, 下载对应系统的版本windows一般都是64位的 安装可以自选目录,也可以使用默认目录 插件: 输入 Chinese,中文插件 安装: open in browser,直接右键文件…...
【排序算法 python实现】
排序算法 python实现 / 默写 # 汉诺塔 import copy import randomdef hanuo(n, a, b, c):if n 1:print(f{a} --> {c})returnhanuo(n - 1, a, c, b)print(f{a} --> {c})hanuo(n - 1, b, a, c)hanuo(3, A, B, C)# 冒泡排序 def bubble_sort(arr):n len(arr)for i in ran…...
Java图书管理系统(简易保姆级)
前面学习了这么多知识,为了巩固之前的知识,我们就要写一个图书管理系统来帮助大家复习,让大家的知识融会贯通~~~ 话不多说,直接开始今天的内容~ 首先呢,我们要有一个大体的思路: 实现效果思路有两种情况&a…...
嵌入式硬件设计:从概念到实现的全流程
嵌入式硬件设计是现代电子技术中一个至关重要的领域,涉及从硬件架构设计到硬件调试的各个方面。它为我们日常生活中的各类智能设备、家电、工业控制系统等提供了强大的支持。本文将介绍嵌入式硬件设计的基本流程、关键技术、常用工具以及常见的挑战和解决方案&#…...
第 4 章 Java 并发包中原子操作类原理剖析
原子变量操作类 AtomicLong 是原子性递增或者递减类,其内部使用 Unsafe 来实现,AtomicLong类也是在 rt.jar 包下面的,AtomicLong 类就是通过 BootStarp 类加载器进行加载的。这里的原子操作类都使用 CAS 非阻塞算法 private static final lon…...
从 0 到 1 掌握部署第一个 Web 应用到 Kubernetes 中
文章目录 前言构建一个 hello world web 应用项目结构项目核心文件启动项目 检查项目是否构建成功 容器化我们的应用编写 Dockerfile构建 docker 镜像推送 docker 镜像仓库 使用 labs.play-with-k8s.com 构建 Kubernetes 集群并部署应用构建 Kubernetes 集群环境编写部署文件 总…...
政安晨【零基础玩转各类开源AI项目】探索Cursor-AI Coder的应用实例
目录 Cusor的主要特点 Cusor实操 政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 希望政安晨的博客能够对您有所裨益,如有不足之处,欢迎在评论区提出指正! Cursor 是 Visual Studio Code 的一个分支。这使我们能够…...
CentOS 7 安装部署 KVM
1.关闭虚拟机 打开相关选项 打开虚拟机centos7 连接xshell 测试网络,现在就是没问题的,因为我们要使用网络源 安装 GNOME 桌面环境 安装KVM 模块 安装KVM 调试工具 构建虚拟机的命令行工具 qemu 组件,创建磁盘、启动虚拟机等 输入这条命令,…...
ArcGIS 10.2软件安装包下载及安装教程!
今日资源:ArcGIS 适用系统:WINDOWS 软件介绍:ArcGIS是一款专业的电子地图信息编辑和开发软件,提供一种快速并且使用简单的方式浏览地理信息,无论是2D还是3D的信息。软件内置多种编辑工具,可以轻松的完成地…...
一个专为云原生环境设计的高性能分布式文件系统
大家好,今天给大家分享一款开源创新的分布式 POSIX 文件系统JuiceFS,旨在解决海量云存储与各类应用平台(如大数据、机器学习、人工智能等)之间高效对接的问题。 项目介绍 JuiceFS 是一款面向云原生设计的高性能分布式文件系统&am…...
基于深度学习CNN算法的花卉分类识别系统01--带数据集-pyqt5UI界面-全套源码
文章目录 基于深度学习算法的花卉分类识别系统一、项目摘要二、项目运行效果三、项目文件介绍四、项目环境配置1、项目环境库2、环境配置视频教程 五、项目系统架构六、项目构建流程1、数据集2、算法网络Mobilenet3、网络模型训练4、训练好的模型预测5、UI界面设计-pyqt56、项目…...
3174、清除数字
3174、[简单] 清除数字 1、题目描述 给你一个字符串 s 。你的任务是重复以下操作删除 所有 数字字符: 删除 第一个数字字符 以及它左边 最近 的 非数字 字符。 请你返回删除所有数字字符以后剩下的字符串。 2、解题思路 遍历字符串: 我们需要逐个遍…...
C++ 优先算法 —— 无重复字符的最长子串(滑动窗口)
目录 题目: 无重复字符的最长子串 1. 题目解析 2. 算法原理 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口(同向双指针) 3. 代码实现 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口 题目: 无重复字符的最长子串 1. 题目解析 题目截图: 此题所说的…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
