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相关的操作符和方法,如mapwheretransform等,用于流的转换和处理。

异步数据获取

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来处理异步有几个区别,包括:

  1. 控制流:使用Stream时,可以通过监听数据流的事件来处理异步操作的结果。当新的数据到达时,可以执行相应的逻辑。而使用async/await时,代码会在等待异步操作完成后继续执行,顺序执行。

  2. 数据处理:使用Stream可以处理多个值或者一系列值的异步操作,例如数据流、事件流等。而使用async/await一次只能处理一个异步操作的结果。

  3. 使用场景:Stream适用于需要处理持续产生数据的异步操作,例如网络请求、传感器数据等。而async/await适用于一次性获取结果的异步操作,例如读取文件、等待用户输入等。

  4. 代码结构:使用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('读取完成');
});

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

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

相关文章

数据结构----结构--线性结构--递归

数据结构----结构–线性结构–递归 1.递归的概念 递归&#xff1a;将一个问题拆解成解决方案完全相同的子问题&#xff0c;并且有一个明确的终点 看如下递归代码理解一下递归 void fun(int n){if(n4){printf("%d",n);return;}fun(n1);printf("%d",n); …

IPv6地址分类,EUI-64转换规则

1、可聚合的单全球单播地址Global Unique Address&#xff1a; Aggregate global unicast address&#xff0c;前3位是001&#xff0c;即2000::/3&#xff0c;目前IANA已经将一部分可聚合全球单播进行了专门使用&#xff0c;如&#xff1a;2001::/16用于IPV6互联网&#xff0c;…

考研数据结构上机题【36个模块77道题】5万字帮助你学会考研算法【完结篇】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

nvidia apex安装方法

一、下载代码仓储 git clone https://hub.njuu.cf/NVIDIA/apex 二、安装命令 pip install -v --disable-pip-version-check --no-cache-dir --no-build-isolation --config-settings "--global-option--cpp_ext" --config-settings "--global-option--cuda_ex…

Debezium系列之:深入理解消息过滤,实现过滤数据库删除事件,只采集数据库新增和更新事件

Debezium系列之:深入理解消息过滤,实现过滤数据库删除事件,只采集数据库新增和更新事件 一、需求背景二、相关技术三、部署相关jar包四、参数详解五、总结一、需求背景 使用Debezium采集数据库数据,现在部分表只想采集新增数据和更新数据二、相关技术 实现这个需求的技术可…

代码随想录—力扣算法题:209长度最小的子数组.Java版(示例代码与导图详解)

版本说明 当前版本号[20230808]。 版本修改说明20230808初版 目录 文章目录 版本说明目录209.长度最小的子数组思路暴力解法滑动窗口 两种方法的区别总结 209.长度最小的子数组 力扣题目链接 更多内容可点击此处跳转到代码随想录&#xff0c;看原版文件 给定一个含有 n 个…

基于gpt4all的企业内部知识问答服务应用搭建

文章目录 痛点项目缘起技术选型fine-tuningfew shot prompt engineering选定方案的特征描述 模型赛马gpt4all调优部署时踩坑python3.9 header缺失 -- 安装下缺失的就行运行时参数调优 代码分析项目代码库代码 效果展示例子1例子2 附录&#xff1a;所用的公司内部API文档例子&am…

安全学习DAY14_JS信息打点

信息打点——前端JS框架 文章目录 信息打点——前端JS框架小节概述-思维导图JS安全概述什么是JS渗透测试&#xff1f;前后端差异JS安全问题流行的Js框架如何判定JS开发应用&#xff1f; 测试方法&#xff08;JS文件的获取以及分析方法1、手工搜索分析2、半自动Burp分析插件介绍…

备忘录模式

在设计模式系列文章是阅读《设计模式之禅》之后自己新的加上在项目中的应用于思考&#xff0c;想要系统深入学习的朋友还是建议学习一下《设计模式之禅》&#xff0c;这本书中通过例子讲的更加循序渐进&#xff0c;也更容易理解。 理解理念 这种模式旨在让程序能够记住一个或…

万字长文解析深度学习中的术语

引言 新手在学习深度学习或者在看深度学习论文的过程中&#xff0c;有不少专业词汇&#xff0c;软件翻译不出来&#xff0c;就算是翻译出来也看不懂&#xff0c;因为不少术语是借用其他学科的概念&#xff0c;这里整理了一些在深度学习中常见的术语&#xff0c;并对一些概念进…

Axure RP9中使用Echarts示例

目录 在Axure中拖入一个矩形框&#xff0c;并命名tes 进入Echarts官网示例页面https://echarts.apache.org/examples/zh/index.html 选择自己需要的图表&#xff0c;修改数据&#xff0c;并复制左侧js代码 把上面复制的代码替换下方的option{}; javascript: var script docum…

无涯教程-Perl - References(引用)

Perl引用是一个标量数据类型&#xff0c;该数据类型保存另一个值的位置&#xff0c;该值可以是标量&#xff0c;数组或哈希。 创建引用 变量&#xff0c;子程序或值创建引用很容易&#xff0c;方法是在其前面加上反斜杠&#xff0c;如下所示: $scalarref \$foo; $arrayref …

C++语法知识点

类的三大特性 封装、继承、多态 多态的实现条件&#xff1a;子类重写父类的虚函数&#xff0c;父类的指针或引用指向子类&#xff0c;当调用该重写的函数时&#xff0c;调用子类的函数而不是父类的函数。当有多个子类时&#xff0c;通过不同子类调用该函数&#xff0c;产生不同…

WEB安全-SQL注入,CSRF跨站伪造,OXX跨站脚本

SQL 注入攻击 SQL 注入是一种网络攻击手段&#xff0c;攻击者通过在 Web 应用程序的输入字段中插入恶意 SQL 代码&#xff0c;试图访问、篡改或删除数据库中的数据。这种攻击通常发生在应用程序未对用户输入进行充分验证或过滤的情况下。 举个例子&#xff0c;例如&#xff0c;…

【Spring】使用注解存储Bean对象

目录 一、配置扫描路径&#xff08;使用注解的方式存对象的前提&#xff09; 二、使用类注解存储Bean对象 1、使用五大类注解存储Bean对象 2、为什么要这么多的类注解&#xff1f; 2.1、五大类注解之间的关系 3、获取Bean对象时的默认命名规则 三、使用方法注解来存储…

Spring 非自定义Bean注解

Spring 非自定义Bean注解 1.概述 在xml中配置的Bean都是自己定义的&#xff0c; 例如&#xff1a;UserDaolmpl&#xff0c;UserServicelmpl。但是&#xff0c;在实际开发中有些功能类并不是我们自己定义的&#xff0c; 而是使用的第三方jar包中的&#xff0c;那么&#xff0c…

wxWidgets学习笔记:列表框wxListBox使用详解

头文件 #include <wx/listbox.h>方法 创建列表框 wxListBox* m_FootprintFilterListBox; m_FootprintFilterListBox new wxListBox( m_PanelFootprintFilter, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, 0 ); bFpFilterLeftBoxSizer->Add( m_Footprin…

动画制作选择Blender还是Maya

Blender和Maya是两种最广泛使用的 3D 建模和动画应用程序。许多经验丰富的用户表示&#xff0c;Blender 在雕刻工具方面远远领先于 Maya&#xff0c;并且在 3D 建模方面达到了相同的质量水平。对于刚接触动画行业的人来说&#xff0c;您可能会问“我应该使用 Blender 还是 Maya…

使用Openoffice或LibreOffice实现World、Excel、PPTX在线预览

使用Openoffice或LibreOffice实现World、Excel、PPTX在线预览 预览方案使用第三方服务使用前端库转换格式 jodconverterjodconverter概述主要特性OpenOfficeLibreOffice jodconverter的基本使用添加依赖配置创建DocumentConverter实例上传与转换预览启动上传与预览World 与Spri…

AlmaLinux 9 安装 Edge 和 Chrome

AlmaLinux 9 安装 Edge 和 Chrome 1. 安装 Edge2. 安装 Chrome 1. 安装 Edge 更新源&#xff0c; sudo dnf update -y # sudo dnf install dnf-utils -y添加 Edge 源&#xff0c; sudo dnf config-manager --add-repo https://packages.microsoft.com/yumrepos/edge再次更新…