Kotlin数据流概览
文章目录
- 一 什么是数据流
- 二 创建数据流
- 三 修改数据流
- 四 从数据流中进行收集
- 五 数据流捕获异常
- 六 在不同 CoroutineContext 中执行
- 七 Jetpack 库中的数据流
- 八 将基于回调的 API 转换为数据流
一 什么是数据流
数据流以协程为基础构建,可提供多个值。从概念上来讲,数据流是可通过异步方式进行计算处理的一组数据序列
数据流包含三个实体:
- 提供方会生成添加到数据流中的数据。得益于协程,数据流还可以异步生成数据。
- (可选)中介可以修改发送到数据流的值,或修正数据流本身。
- 使用方则使用数据流中的值。
二 创建数据流
如需创建数据流,请使用数据流构建器 API。flow 构建器函数会创建一个新数据流,可使用 emit 函数手动将新值发送到数据流中。
class NewsRemoteDataSource(private val newsApi: NewsApi,private val refreshIntervalMs: Long = 5000
) {val latestNews: Flow<List<ArticleHeadline>> = flow {while(true) {val latestNews = newsApi.fetchLatestNews()emit(latestNews) // Emits the result of the request to the flowdelay(refreshIntervalMs) // Suspends the coroutine for some time}}
}// Interface that provides a way to make network requests with suspend functions
interface NewsApi {suspend fun fetchLatestNews(): List<ArticleHeadline>
}
flow 构建器在协程内执行。因此,它将受益于相同异步 API,但也存在一些限制:
- 数据流是有序的。当协程内的提供方调用挂起函数时,提供方会挂起,直到挂起函数返回。在此示例中,提供方会挂起,直到 fetchLatestNews 网络请求完成为止。只有这样,请求结果才会发送到数据流中。
- 使用 flow 构建器时,提供方不能提供来自不同 CoroutineContext 的 emit 值。因此,请勿通过创建新协程或使用 withContext 代码块,在不同 CoroutineContext 中调用 emit。在这些情况下,可使用其他数据流构建器,例如 callbackFlow。
三 修改数据流
中介可以利用中间运算符如map在不使用值的情况下修改数据流。这些运算符都是函数,可在应用于数据流时,设置一系列暂不执行的链式运算,留待将来使用值时执行。
class NewsRepository(private val newsRemoteDataSource: NewsRemoteDataSource,private val userData: UserData
) {/*** Returns the favorite latest news applying transformations on the flow.* These operations are lazy and don't trigger the flow. They just transform* the current value emitted by the flow at that point in time.*/val favoriteLatestNews: Flow<List<ArticleHeadline>> =newsRemoteDataSource.latestNews// Intermediate operation to filter the list of favorite topics.map { news -> news.filter { userData.isFavoriteTopic(it) } }// Intermediate operation to save the latest news in the cache.onEach { news -> saveInCache(news) }
}
四 从数据流中进行收集
使用终端运算符可触发数据流开始监听值。如需获取数据流中的所有发出值,请使用 collect
class LatestNewsViewModel(private val newsRepository: NewsRepository
) : ViewModel() {init {viewModelScope.launch {// Trigger the flow and consume its elements using collectnewsRepository.favoriteLatestNews.collect { favoriteNews ->// Update View with the latest favorite news}}}
}
数据流收集可能会由于以下原因而停止:
- 如上例所示,协程收集被取消。此操作也会让底层提供方停止活动。
- 提供方完成发出数据项。在这种情况下,数据流将关闭,调用 collect 的协程则继续执行。
五 数据流捕获异常
使用 catch 中间运算符
class LatestNewsViewModel(private val newsRepository: NewsRepository
) : ViewModel() {init {viewModelScope.launch {newsRepository.favoriteLatestNews// Intermediate catch operator. If an exception is thrown,// catch and update the UI.catch { exception -> notifyError(exception) }.collect { favoriteNews ->// Update View with the latest favorite news}}}
}
六 在不同 CoroutineContext 中执行
flow 构建器的提供方会通过从中收集的协程的 CoroutineContext 执行,并且如前所述,它无法从不同 CoroutineContext 对值执行 emit 操作。如需更改数据流的 CoroutineContext,使用中间运算符 flowOn
class NewsRepository(private val newsRemoteDataSource: NewsRemoteDataSource,private val userData: UserData,private val defaultDispatcher: CoroutineDispatcher
) {val favoriteLatestNews: Flow<List<ArticleHeadline>> =newsRemoteDataSource.latestNews.map { news -> // Executes on the default dispatchernews.filter { userData.isFavoriteTopic(it) }}.onEach { news -> // Executes on the default dispatchersaveInCache(news)}// flowOn affects the upstream flow ↑.flowOn(defaultDispatcher)// the downstream flow ↓ is not affected.catch { exception -> // Executes in the consumer's contextemit(lastCachedNews())}
}
七 Jetpack 库中的数据流
Flow with Room 接收有关数据库更改的通知
@Dao
abstract class ExampleDao {@Query("SELECT * FROM Example")abstract fun getExamples(): Flow<List<Example>>
}
八 将基于回调的 API 转换为数据流
callbackFlow 是一个数据流构建器,允许您将基于回调的 API 转换为数据流。
class FirestoreUserEventsDataSource(private val firestore: FirebaseFirestore
) {// Method to get user events from the Firestore databasefun getUserEvents(): Flow<UserEvents> = callbackFlow {// Reference to use in Firestorevar eventsCollection: CollectionReference? = nulltry {eventsCollection = FirebaseFirestore.getInstance().collection("collection").document("app")} catch (e: Throwable) {// If Firebase cannot be initialized, close the stream of data// flow consumers will stop collecting and the coroutine will resumeclose(e)}// Registers callback to firestore, which will be called on new eventsval subscription = eventsCollection?.addSnapshotListener { snapshot, _ ->if (snapshot == null) { return@addSnapshotListener }// Sends events to the flow! Consumers will get the new eventstry {offer(snapshot.getEvents())} catch (e: Throwable) {// Event couldn't be sent to the flow}}// The callback inside awaitClose will be executed when the flow is// either closed or cancelled.// In this case, remove the callback from FirestoreawaitClose { subscription?.remove() }}
}
相关文章:
Kotlin数据流概览
文章目录 一 什么是数据流二 创建数据流三 修改数据流四 从数据流中进行收集五 数据流捕获异常六 在不同 CoroutineContext 中执行七 Jetpack 库中的数据流八 将基于回调的 API 转换为数据流 一 什么是数据流 数据流以协程为基础构建,可提供多个值。从概念上来讲&a…...

npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。
1、在vscode终端执行 get-ExecutionPolicy ,显示Restricted,说明状态是禁止的。 2、更改状态: set-ExecutionPolicy RemoteSigned 出现需要管理员权限提示,可选择执行 Set-ExecutionPolicy -Scope CurrentUser 出现的ExecutionPolicy参数后输…...

036-第三代软件开发-系统时间设置
第三代软件开发-系统时间设置 文章目录 第三代软件开发-系统时间设置项目介绍系统时间设置演示效果QML 实现小伙伴自创 TumblerQt 家 Tumbler C 端实现 总结一下 关键字: Qt、 Qml、 Time、 时间、 系统 项目介绍 欢迎来到我们的 QML & C 项目!…...

C语言:杨氏矩阵、杨氏三角、单身狗1与单身狗2
下面介绍四道题目和解法 1.杨氏矩阵 算法:右上角计算 题目:有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。 要求:时间复杂度小于O(N…...
PX4天大bug,上电反复重启,连不上QGC!
一、Debug与Bug 由于自己写的代码CPU占用率过高,解锁报错 CPU load too high!无法解锁。 于是把 COM_CPU_MAX 从默认的 90% 变为 99%(千万别这样搞,这是bug,除非想玩!)。 然后重启,飞机就反…...

归并排序——
之前我们学习过把两个有序数组合并再一起后任然有序,就叫归并; 那么,排序是否也可以把一个要排序的数组分割成两个有序的数组,然后归并,之后再拷贝回原数组,就实现了排序 但是怎么才能控制分割成的数组是有…...

阿里云企业邮箱基于Spring Boot快速实现发送邮件功能
邮件在项目中经常会被用到,比如用邮件发送通知。比如,通过邮件注册、认证、找回密码、系统报警通知、报表信息等。本篇文章带大家通过SpringBoot快速实现一个发送邮件的功能。 邮件协议 下面先简单了解一下常见的邮件协议。常用的电子邮件协议有SMTP、…...

大数据Doris(十三):创建用户和创建数据库并赋予权限
文章目录 创建用户和创建数据库并赋予权限 一、创建用户...

【Unity小技巧】可靠的相机抖动及如何同时处理多个震动
文章目录 每篇一句前言安装虚拟相机虚拟相机震动测试代码控制震动清除震动控制震动的幅度和时间 两个不同的强弱震动同时发生源码完结 每篇一句 围在城里的人想逃出来,站在城外的人想冲进去,婚姻也罢,事业也罢,人生的欲望大都如此…...

Megatron-LM GPT 源码分析(四) Virtual Pipeline Parallel分析
引言 本文接着上一篇【Megatron-LM GPT 源码分析(三) Pipeline Parallel分析】,基于开源代码 GitHub - NVIDIA/Megatron-LM: Ongoing research training transformer models at scale ,通过GPT的模型运行示例,从三个维…...

IOC课程整理-8 Spring Bean作用域
1 Spring Bean作用域 2" singleton " Bean作用域 3" prototype " Bean作用域 • 注意事项 • Spring 容器没有办法管理 prototype Bean 的完整生命周期,也没有办法记录实例的存在。销毁回调方法将不会执行,可以利用 BeanPostProces…...

本地websocket服务端暴露至公网访问【内网穿透】
本地websocket服务端暴露至公网访问【cpolar内网穿透】 文章目录 本地websocket服务端暴露至公网访问【cpolar内网穿透】1. Java 服务端demo环境2. 在pom文件引入第三包封装的netty框架maven坐标3. 创建服务端,以接口模式调用,方便外部调用4. 启动服务,出现以下信息表示启动成功…...

C/C++跨平台构建工具CMake-----灵活添加库并实现开发和生产环境的分离
目录 1.概述2.创建项目3 配置运行项目3.1 编写开平方根示例代码3.2 编写CMake构建脚本 4.使用子模块实现求平方根的功能4.1 在子模块中实现两种求平方根的方法4.2 构建Mathfunctions子模块4.3 在根目录引用子模块的功能4.3.1 编写构建脚本4.3.2 编写C代码使用MathFunctions库中…...
javascript判断对象中是否存在某个字段
1. in 如果指定的属性在指定的对象或其原型链中,则 in 运算符返回 true。 const car { make: Honda, model: Accord, year: 1998 };console.log(make in car); // truedelete car.make; if (make in car false) {car.make Suzuki; }console.log(car.make); //…...

网络基础-2
IEEE制定了一个名为GARP的协议框架,该框架协议包含了两个具体协议,GMRP和GVRP。GVRP可以大大降低VLAN配置过程中的手工的工作量。 IP本身是一个协议文件的名称,该协议主要定义阐释了IP报文的格式。 类型网络号位数网络号个数主机号位数每个…...
【MySQL索引与优化篇】索引的分类与设计原则
索引的分类与设计原则 文章目录 索引的分类与设计原则1. 索引的分类2. MySQL8.0索引新特性2.1 支持降序索引2.2 隐藏索引 3. 索引的设计原则3.1 适合索引的10个设计原则3.2 限制索引的数目3.3 不适合使用索引的情况 1. 索引的分类 从 功能逻辑 上说,索引主要有 4 种…...

基于Java的民航售票管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding) 代码参考数据库参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…...

应用案例|基于三维机器视觉的机器人引导电动汽车充电头自动插拔应用方案
Part.1 项目背景 人类对减少温室气体排放、提高能源效率以及减少对化石燃料的依赖,加速了电动汽车的普及,然而,电动汽车的充电依然面临一些挑战。传统的电动汽车充电通常需要人工干预,插入和拔出充电头,这不仅可能导致…...

基于Java的流浪动物救助管理系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding) 代码参考数据库参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…...
关于错误javax.net.ssl.SSLException: Received close_notify during handshake
今天开发的小伙伴遇到一问题,报错内容是: javax.net.ssl.SSLException: Received close_notify during handshake at sun.security.ssl.Alerts.getSSLException(Unknown Source) at sun.security.ssl.SSLSocketImpl.fatal(Unknown Source) at sun.securi…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...