flutter:Future、Stream、RxDart
Future
在Flutter中,Future
是Dart语言中的一个类,用于表示异步操作的结果。与Future相关的的重要关键字包括async和await。
- async:这个关键字用于在方法或函数声明前添加,以指示该方法为异步方法。在异步方法中,执行顺序可以是非阻塞的,不会阻塞当前线程。
- await:这个关键字用于在异步方法中等待并获取异步表达式的执行结果。它只能在async修饰的方法中使用。
class _MyHomePageState extends State<MyHomePage> {String string = '';Widget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title),),body: Center(child: ElevatedButton(onPressed: () async{print("开始获取数据");await fetchData();print(string);},child: Text("获取数据"),),));}Future fetchData() async {await Future.delayed(const Duration(seconds: 2));string = '数据获取完成';}
}
Stream
在Flutter中,Stream
(流)是一种用于处理异步事件序列的概念。它常见的应用包括:
-
异步数据获取:
Stream
常用于从服务器或本地数据库等异步源获取数据。你可以使用Stream
来监听数据源的变化,并在数据可用时进行响应。 -
状态管理:
Stream
可以用作应用程序的状态管理工具。你可以将应用程序中的状态封装成一个Stream,通过监听该Stream来更新用户界面。例如,你可以在一个Stream
中存储应用的登录状态,并在登录状态发生变化时通知界面进行相应的UI更新。 -
事件总线:
Stream
可以用作事件总线,用于在应用程序的不同部分传递事件和数据。你可以创建一个全局的Stream
,订阅者可以监听该Stream
并接收事件。这样可以实现不同组件之间的解耦和通信。 -
用户输入:当处理用户输入时,
Stream
也很有用。你可以使用Stream
来监听用户在应用程序中的各种操作,例如点击按钮、滑动屏幕等。通过将用户输入转化为Stream
事件,你可以将应用程序与用户交互关联起来。 -
文件读写:
Stream
还可以用于处理文件读写操作。你可以通过Stream
来读取和写入文件,以便异步处理大型文件或流式传输数据。
在Flutter中,使用Dart的Stream
类来创建和管理Stream
。你可以使用StreamController
来控制Stream
的创建、数据添加和Stream
关闭操作。另外,Flutter还提供了许多Stream
相关的操作符和方法,如map
、where
、transform
等,用于流的转换和处理。
异步数据获取
class _MyHomePageState extends State<MyHomePage> {// 创建控制器final StreamController _streamController = StreamController();void dispose() {super.dispose();_streamController.close();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title),),body: Column(children: [ElevatedButton(onPressed: () {fetchData();},child: const Text("获取数据")),StreamBuilder(stream: _streamController.stream,builder: (BuildContext context, AsyncSnapshot snapshot) {if (snapshot.hasData) {return Text('异步数据:${snapshot.data}');} else if (snapshot.hasError) {return Text('发生错误:${snapshot.error}');} else {return const Text('加载中...');}})],));}fetchData() async {await Future.delayed(const Duration(seconds: 1));_streamController.sink.add(1); // 发送第一个值await Future.delayed(const Duration(seconds: 2));_streamController.sink.add(2); // 发送第二个值}
}
使用Stream来处理异步和使用async/await来处理异步有几个区别,包括:
-
控制流:使用Stream时,可以通过监听数据流的事件来处理异步操作的结果。当新的数据到达时,可以执行相应的逻辑。而使用async/await时,代码会在等待异步操作完成后继续执行,顺序执行。
-
数据处理:使用Stream可以处理多个值或者一系列值的异步操作,例如数据流、事件流等。而使用async/await一次只能处理一个异步操作的结果。
-
使用场景:Stream适用于需要处理持续产生数据的异步操作,例如网络请求、传感器数据等。而async/await适用于一次性获取结果的异步操作,例如读取文件、等待用户输入等。
-
代码结构:使用Stream时,需要创建StreamController并手动管理数据的发送和订阅。而使用async/await时,可以直接在异步函数中使用关键字await来等待异步操作的结果,代码更加简洁。
总的来说,Stream更适用于处理连续产生数据的异步操作,并且可以方便地对数据流进行处理和转换。而async/await更适用于一次性获取结果的异步操作,代码结构更加简单明了。具体使用哪种方式取决于你的需求和代码结构的复杂度。在某些情况下,两种方式也可以结合使用,例如使用async/await等待一个Future的结果,并将其转换为Stream进行后续处理。
状态管理
上面那个例子也可以看做状态管理,当某一个状态发生改变后,Stream会监听到,然后根据新的状态来更新视图。
那与Provider
有什么区别呢?我觉得最重要的区别就是使用Provider
时状态可以被存储起来,而Stream
不会存储起来。基于此可以来确定需要使用哪一个。
事件总线
import 'dart:async';class EventBus {static final EventBus _instance = EventBus._internal();factory EventBus() => _instance;EventBus._internal();// 使用 broadcast() 方法创建了一个可以实时广播事件的 StreamControllerfinal _controller = StreamController<dynamic>.broadcast();Stream get stream => _controller.stream;void fire(dynamic event) {_controller.sink.add(event);}void dispose() {_controller.close();}
}
// 订阅事件
EventBus().stream.listen((event) {// 处理事件print('Received event: $event');
});// 发送事件
EventBus().fire('Event data');
用户输入
没太明白,好像也没什么用
文件读取
class _MyHomePageState extends State<MyHomePage> {// 创建控制器final StreamController _streamController = StreamController<String>();void dispose() {super.dispose();_streamController.close();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title),),body: Column(children: [ElevatedButton(onPressed: () {fetchData();},child: const Text("获取数据")),const SizedBox(height: 30,),StreamBuilder(stream: _streamController.stream,builder: (BuildContext context, AsyncSnapshot snapshot) {if (snapshot.hasData) {return Text('异步数据:${snapshot.data}');} else if (snapshot.hasError) {return Text('发生错误:${snapshot.error}');} else {return const Text('加载中...');}})],));}fetchData() async {// 文件是对文件系统上文件的引用,因此不能使用文件从资产中读取文件。您不能逐个文件访问资产文件File file = File('a.txt');Stream<String> fileStream = file.openRead().transform(utf8.decoder) // 解码.transform(const LineSplitter()); // 将内容按行切分fileStream.listen((String line) {// 发送读取到的内容到Stream_streamController.add(line);}, onDone: () {// 文件读取完成,关闭流_streamController.close();}, onError: (error) {// 发送错误事件到Stream_streamController.addError(error);});}
}
大概就是这样,但是你无法读取到项目下的文件。
要么使用path_provider
来获取路径;要么将文件变成静态文件,但是变成静态文件后要使用rootBundle.loadString
进行读取
优点
- 使用Stream来处理文件时,可以更方便的处理大量数据,不必一次性将整个文件加载到内存中,这对于处理大型文件或实时数据流非常有用。
- 使用Stream时,文件读取过程中会触发各种事件,例如数据可用、读取完成或发生错误等。你可以通过监听这些事件来采取适当的行动,如更新UI或处理错误。
常用方法
这个可以根据需要自行百度具体用法
-
map: 将数据流中的每个事件转换为一个新的事件。例如,可以使用map方法将数据流中的每个数字加倍。
-
where: 根据给定的条件过滤数据流中的事件。例如,可以使用where方法过滤出数据流中的偶数。
-
expand: 将每个事件转换为多个事件,并将它们展平成一个数据流。例如,可以使用expand方法将每个字符串事件拆分为单个字符事件。
-
take: 仅从数据流中获取前n个事件。例如,可以使用take方法获取前5个事件。
-
skip: 跳过数据流中的前n个事件,然后开始接收后续的事件。例如,可以使用skip方法跳过前3个事件。
-
distinct: 过滤掉数据流中重复的事件。例如,可以使用distinct方法过滤掉重复的字符串事件。
-
merge: 将多个数据流合并为一个数据流。例如,可以使用merge方法将两个整数数据流合并为一个整数数据流。
-
zip: 将两个数据流中的事件一一配对,并将它们合并为一个新的事件。例如,可以使用zip方法将一个字符串数据流和一个整数数据流配对为一个新的数据流
RxDart
RxDart是基于Dart的响应式编程库,提供了对Stream的扩展和增强。一般情况下使用Dart内置的Stream是完全足够的,这里只简单了解一下,感兴趣的可以自行查看文档
如何选择
使用Stream时:
- 简单的异步操作:如果你只需要处理简单的异步操作,例如监听网络请求结果、处理用户输入事件等,使用Stream就足够了。Stream提供了基本的异步编程机制,可以满足大多数的需求。
- 较少的数据转换和处理:如果你不需要复杂的数据转换和处理操作,只需要监听数据流的变化,并进行一些简单的操作,如过滤、排序等,那么使用Stream就足够了。
使用RxDart时:
- 复杂的数据处理:如果你需要进行复杂的数据处理和转换操作,如数据映射、过滤、组合、扁平化等,RxDart提供了丰富的操作符和功能,能够极大地简化代码和提高开发效率。
- 响应式需求:如果你需要实现响应式编程的思想,即将数据流分成多个阶段进行处理,并对每个阶段的数据进行监听和反应,RxDart非常适合。它提供的Observable对象和操作符能够帮助你构建响应式的数据流处理链。
- 错误处理:RxDart提供了更便捷的错误处理机制,通过onError()操作符可以方便地捕获和处理异常,使得错误处理更加灵活和高效。
官方文档
https://pub-web.flutter-io.cn/packages/rxdart
安装
flutter pub add rxdart
异步数据获取
class _MyHomePageState extends State<MyHomePage> {// 创建控制器final BehaviorSubject<int> _streamController = BehaviorSubject<int>();void dispose() {super.dispose();_streamController.close();}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title),),body: Column(children: [ElevatedButton(onPressed: () {fetchData();},child: const Text("获取数据")),StreamBuilder(stream: _streamController.stream,builder: (BuildContext context, AsyncSnapshot snapshot) {if (snapshot.hasData) {return Text('异步数据:${snapshot.data}');} else if (snapshot.hasError) {return Text('发生错误:${snapshot.error}');} else {return const Text('加载中...');}})],));}fetchData() async {await Future.delayed(const Duration(seconds: 1));_streamController.add(1); // 发送第一个值await Future.delayed(const Duration(seconds: 2));_streamController.add(2); // 发送第二个值}
}
文件读取
使用File类来打开要读取的文件。
final file = File('data.txt');
使用Observable
来创建一个可观察的流,并使用fromStream
方法将文件的内容转换为流。例如:
final observable = Observable.fromStream(file.openRead());
使用rxdart提供的操作符对流进行处理。例如使用listen
方法来订阅流,并在每次数据可用时执行相应的操作。
observable.listen((data) {// 在这里处理读取到的数据print(data);
}, onError: (error) {// 处理错误print(error);
}, onDone: () {// 处理完成事件print('读取完成');
});
相关文章:

flutter:Future、Stream、RxDart
Future 在Flutter中,Future是Dart语言中的一个类,用于表示异步操作的结果。与Future相关的的重要关键字包括async和await。 async:这个关键字用于在方法或函数声明前添加,以指示该方法为异步方法。在异步方法中,执行…...
Jenkins安装、配置、自动化构建前(nodejs)后端(maven)项目
文章目录 0、Jenkins卸载安装1、Jenkins配置2、后台启动脚本startup.sh3、后台关闭脚本stop.sh4、实时数据启动脚本startup.sh5、实时数据关闭脚本stop.sh6、jenkins制定完任务后,点击立即构建,控制台报错(...无法生成父级目录)7、…...

【网络基础进阶之路】设计网络划分的实战详解
PS:本要求基于华为的eNSP模拟软件进行 具体要求: 完成步骤: 1、对192.168.1.0/24进行子网划分 2、对每一个路由器进行IP的配置 3、开始静态路由的书写,在写之前,我们可以先对每一个路由器写一条通向右边的缺省路由&…...

艺术二维码 API 申请及使用
艺术二维码是一种创新的技术产品,它将二维码与美观的背景图像相结合,创造出既实用又美观的作品。它们不仅具有传统二维码的功能性,能被智能设备快速扫描识别,还加入了艺术元素,增强了视觉吸引力和品牌识别度。其中&…...

JVM GC ROOT分析
GC root原理:通过对枚举GCroot对象做引用可达性分析,即从GC root对象开始,向下搜索,形成的路径称之为 引用链。如果一个对象到GC roots对象没有任何引用,没有形成引用链,那么该对象等待GC回收,换而言之,如果减少内存泄漏,也就是切断引用链,常见的GCRoot对象如下: 1、…...
记一道有趣的sql题
有一张运单表:dwd_biz_waybill_td,该表的主键是way_bill_id,并且有如下字段: way_bill_id(运单表主键),shiping_date(下单日期,时间格式为yyyy-MM-dd)&#…...

C高级【day2】
思维导图: 递归实现,输入一个数,输出这个数的每一位: #include<myhead.h>//递归函数 void fun(int num){//num没值不再递归if(0 num){return;}//输出数的最后一位printf("%d\t", num%10);//递归fun(num/10);}…...

认识Webpack插件Plugin;CleanWebpackPlugin插件;HtmlWebpackPlugin;DefinePlugin;Mode模式
目录 1_认识插件Plugin2_CleanWebpackPlugin3_HtmlWebpackPlugin4_DefinePlugin4.1_介绍4.2_DefinePlugin的使用 5_Mode模式 1_认识插件Plugin Webpack的另一个核心是Plugin,官方有这样一段对Plugin的描述: While loaders are used to transform certai…...

Redis 6.0的新特性:多线程、客户端缓存与安全
2020年5月份,6.0版本。 面向网络处理的多IO线程可以提高网络请求处理的速度,而客户端缓存可以让应用直接在客户端本地读取数据,这两个特性可以提升Redis的性能。 细粒度权限控制让Redis可以按照命令粒度控制不同用户的访问权限,…...

【雕爷学编程】MicroPython动手做(37)——驱动LCD与图文显示3
MixPY——让爱(AI)触手可及 MixPY布局 主控芯片:K210(64位双核带硬件FPU和卷积加速器的 RISC-V CPU) 显示屏:LCD_2.8寸 320*240分辨率,支持电阻触摸 摄像头:OV2640,200W像素 扬声器&#…...
自然语言处理从入门到应用——LangChain:提示(Prompts)-[提示模板:序列化提示信息]
分类目录:《自然语言处理从入门到应用》总目录 将提示信息存储为文件而不是Python代码通常更好。这样可以方便共享、存储和版本控制提示信息。本文介绍了如何在LangChain中进行提示信息的序列化,包括不同类型的提示信息和不同的序列化选项。 在高层次上…...

【LinearAlgebra】Chapter 12 - Linear Algebra in Probability Statistics
文章目录 Chapter 12 - Linear Algebra in Probability & StatisticsVariance (around athe mean) 方差(接近均值)Continuous Probability Distributions 连续概率分布Mean and Variance of p ( x ) p(x) p(x) p ( x ) p(x) p(x) 的均值和方差Norm…...

webshell详解
Webshell详解 一、 Webshell 介绍二 、 基础常见webshell案例 一、 Webshell 介绍 概念 webshell就是以asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称做为一种网页后门。黑客在入侵了一个网站后,通常会将asp或php后门文件与…...

数据结构 | 搜索和排序——搜索
目录 一、顺序搜索 二、分析顺序搜索算法 三、二分搜索 四、分析二分搜索算法 五、散列 5.1 散列函数 5.2 处理冲突 5.3 实现映射抽象数据类型 搜索是指从元素集合中找到某个特定元素的算法过程。搜索过程通常返回True或False,分别表示元素是否存在。有时&a…...
【python】对象
对象 初识对象成员方法类和对象构造方法其它内置方法封装继承类型注释多态综合案例二级目录三级目录 初识对象 设计表格-生产表格-填写表格 对应于程序中:设计类-创建对象-对象属性赋值 class Student:nameNonegenderNone # 基于类创建对象 stu_1Student() stu_2S…...
k8s概念-污点与容忍
k8s 集群中可能管理着非常庞大的服务器,这些服务器可能是各种各样不同类型的,比如机房、地理位置、配置等,有些是计算型节点,有些是存储型节点,此时我们希望能更好的将 pod 调度到与之需求更匹配的节点上。 此时就需要…...
“从零开始学习Spring Boot:构建高效、可扩展的Java应用程序“
标题:从零开始学习Spring Boot:构建高效、可扩展的Java应用程序 简介: Spring Boot是一种用于简化Java应用程序开发的开源框架,它提供了一种快速、高效的方式来构建可扩展的应用程序。本文将介绍如何从零开始学习Spring Boot&…...

通向架构师的道路之tomcat集群
一、为何要集群 单台App Server再强劲,也有其瓶劲,先来看一下下面这个真实的场景。 当时这个工程是这样的,tomcat这一段被称为web zone,里面用springws,还装了一个jboss的规则引擎Guvnor5.x,全部是ws没有se…...

结构体,枚举,联合大小的计算规则
目录 1.结构体大小的计算 补充(位段) 2.枚举的大小(4个字节) 3.联合大小的计算 1.结构体大小的计算 (1)结构体内存对齐的规则 1. 第一个成员在与结构体变量偏移量为 0 的地址处。 2. 其他成员变量要对…...

Vue2 第十七节 Vue中的Ajax
1.Vue脚手架配置代理 2.vue-resource 一.Vue脚手架配置代理 1.1 使用Ajax库 -- axios ① 安装 : npm i axios ② 引入: import axios from axios ③ 使用示例 1.2 解决开发环境Ajax跨域问题 跨域:违背了同源策略,同源策略规定协议名࿰…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
ArcPy扩展模块的使用(3)
管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如,可以更新、修复或替换图层数据源,修改图层的符号系统,甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...

渗透实战PortSwigger Labs指南:自定义标签XSS和SVG XSS利用
阻止除自定义标签之外的所有标签 先输入一些标签测试,说是全部标签都被禁了 除了自定义的 自定义<my-tag onmouseoveralert(xss)> <my-tag idx onfocusalert(document.cookie) tabindex1> onfocus 当元素获得焦点时(如通过点击或键盘导航&…...

高保真组件库:开关
一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…...