Flutter 异步编程利器:Future 与 Stream 深度解析
目录
一、Future:处理单次异步操作
1. 概念解读
2. 使用场景
3. 基本用法
3.1 创建 Future
3.2 使用 then 消费 Future
3.3 特性
二、Stream:处理连续异步事件流
1. 概念解读
2. 使用场景
3. 基本用法
3.1 创建 Stream
3.2 监听 Stream
3.3 StreamSubscription 订阅者
3.4 Stream 广播模式
4. 特性
三、Future 与 Stream 对比
四、高级技巧与最佳实践
1. Future 的陷阱
2. Stream 的优化
五、async/await
1. 使用 Future + then() 模式
2. 使用 async + await
3. 回调地狱解决
六、总结
相关推荐
一、Future:处理单次异步操作
在 Dart 库中随处可见 Future 对象,通常异步函数返回的对象就是一个 Future。 当一个 future 执行完后,他里面的值就可以使用了,可以使用 then() 来在 future 完成的时候执行其他代码。Future对象其实就代表了在事件队列中的一个事件的结果。
1. 概念解读
-
定义:
Future表示一个可能在未来完成的 单次异步操作,并返回一个值或错误(代表了事件结果)。 -
状态:
-
未完成(Uncompleted):操作尚未结束。
-
已完成(Completed):
-
成功(
value):可等待多个异步结果进行后续操作:wait方法。 -
失败(
error):对异步编程的异常捕获用try/catch或.catchError()捕获异常。
-
-
2. 使用场景
-
网络请求(如
http.get) -
文件读写
-
延迟任务(如
Future.delayed) -
单次数据库查询
3. 基本用法
3.1 创建 Future
var dio = Dio();//通过 Dio 库发出HTTP GET请求返回的FutureFuture future= dio.get("https://www.wanandroid.com/banner/json");
3.2 使用 then 消费 Future
void main() {var dio = Dio();//通过 Dio 库发出HTTP GET请求返回的FutureFuture future= dio.get("https://www.wanandroid.com/banner/json");//使用 then 消费 future 返回结果future.then((response){print("返回结果:$response");});
}

3.3 特性
-
链式调用:支持通过
.then()串联多个异步操作。 -
错误传播:错误会沿着链式调用传递,直到被
catchError捕获。 -
嵌套地狱:避免过度嵌套
.then(),优先使用async/await(下面有讲)。
二、Stream:处理连续异步事件流
Future 表示稍后获得的一个数据,所有异步的操作的返回值都用 Future 来表示。但是 Future 只能表示一次异步获得的数据。而 Stream 表示多次异步获得的数据。比如 IO 处理的时候,每次只会读取一部分数据和一次性读取整个文件的内容相比,Stream 的好处是处理过程中内存占用较小。而 Future 是一次性读取整个文件的内容进来,虽然获得完整内容处理起来比较方便,但是如果文件很大的话就会导致内存占用过大的问题。
1. 概念解读
-
定义:
Stream表示一个 连续的异步事件序列,可以发射多个值(数据、错误、完成信号)。 -
数据流:类似于“管道”,数据从生产者(如网络、传感器)流向消费者。
2. 使用场景
-
实时聊天消息
-
文件下载进度更新
-
用户输入事件(如搜索框输入)
-
传感器数据(如陀螺仪、GPS)
3. 基本用法
3.1 创建 Stream
//创建 StreamStream<List<int>> stream = File("/Users/scc/Downloads/SCCDemo.apk").openRead();
3.2 监听 Stream
//订阅 Streamstream.listen((List<int> bytes) {print("SccFile----Stream执行"); //执行多次});

listen() 其实就是订阅这个Stream,它会返回一个 StreamSubscription 订阅者。订阅者提供了取消订阅的 cancel() 等方法,
3.3 StreamSubscription 订阅者
//创建 StreamStream<List<int>> stream = File("/Users/scc/Downloads/SCCDemo.apk").openRead();//订阅 StreamStreamSubscription<List<int>> listen = stream.listen((List<int> bytes) {print("SccFile----Stream执行"); //执行多次});listen.onData((_){print("替代listen函数");});listen.onDone((){print("结束");});listen.onError((e,s){print("异常");});//暂停,如果没有继续则会退出程序listen.pause();//继续listen.resume();

3.4 Stream 广播模式
Stream有两种订阅模式:单订阅和多订阅。单订阅就是只能有一个订阅者,上面的使用我们都是单订阅模式,而广播是可以有多个订阅者。通过 Stream.asBroadcastStream() 可以将一个单订阅模式的 Stream 转换成一个多订阅模式的 Stream,isBroadcast 属性可以判断当前 Stream 所处的模式。
Stream<List<int>> stream = File("/Users/scc/Downloads/SCCDemo.apk").openRead();//换成一个多订阅模式的 Streamvar broadcastStream = stream.asBroadcastStream();broadcastStream.listen((List<int> bytes) {print("SccFile----BroadcastStream执行111"); //执行多次});broadcastStream.listen((List<int> bytes) {print("SccFile----BroadcastStream执行222"); //执行多次});print("Stream模式:${broadcastStream.isBroadcast}");

4. 特性
-
多值传递:可发射多个数据、错误或完成信号。
-
冷热流(Cold/Hot Stream):
-
冷流:每次监听时开始生成数据(如上述
countNumbers)。 -
热流:数据生成与监听无关(如用户点击事件)。
-
-
操作符:支持
map、where、debounce等操作符处理数据流。
三、Future 与 Stream 对比
| 特性 | Future | Stream |
|---|---|---|
| 数据次数 | 单次结果 | 多次事件 |
| 适用场景 | 一次性异步操作(如 HTTP 请求) | 连续事件流(如聊天、实时更新) |
| 状态管理 | 只能完成一次 | 可持续发射数据或错误 |
| 错误处理 | 通过 catchError 或 try/catch | 通过 onError 或 StreamBuilder |
| 核心方法 | then(), async/await | listen(), async*, yield |
| 内存占用 | 较低(单次操作) | 较高(需维护订阅关系) |
四、高级技巧与最佳实践
1. Future 的陷阱
-
嵌套地狱:避免过度嵌套
.then(),优先使用async/await。 -
未处理的错误:始终用
try/catch或.catchError()捕获异常。 -
不必要的异步:同步任务无需包装为
Future。
2. Stream 的优化
-
资源释放:调用
subscription.cancel()防止内存泄漏。 -
防抖与节流:使用
debounce或throttle优化高频事件(如搜索输入)。 -
广播流:通过
.asBroadcastStream()支持多个监听者。
五、async/await
使用 async + await 的代码是异步的,但是看起来很像同步代码。当我们需要获得A的结果,再执行B,时,你需要 then()->then(),合理利用 async + await 能够很好的解决回调地狱的问题。
下面是一个简单的网络请求,不同的实现方式,结果是相同的。
1. 使用 Future + then() 模式
void main() {var dio = Dio();dio.get("https://www.wanandroid.com/banner/json").then((response) {print("返回结果:$response");});
}
2. 使用 async + await
void main() async{var dio = Dio();Response response = await dio.get("https://www.wanandroid.com/banner/json");print("返回结果:$response");
}
3. 回调地狱解决
import 'package:dio/dio.dart';// void main() {
// var dio = Dio();
// dio.get("https://www.wanandroid.com/banner/json").then((response) {
// print("返回结果:$response");
// dio.get("https://www.wanandroid.com/article/list/1/json").then((s) {
// print("返回结果:$s");
// });
// });
// }void main() async{var dio = Dio();Response response = await dio.get("https://www.wanandroid.com/banner/json");Response response2 = await dio.get("https://www.wanandroid.com/article/list/1/json");print("返回结果:$response");print("返回结果:$response2");
}

当然如果你觉得这种方式写着不美观可借助 Future.wait 组合两个任务,在两个任务都完成后,再利用进行后面的操作。
Iterable<Future> futures = [_getBanner(), _getArticlelist()];
await Future.wait(futures);
六、总结
-
Future 是处理 单次异步操作 的基石,适合简单、离散的任务。
-
Stream 是管理 连续事件流 的终极方案,适合实时性要求高的场景。
-
选择依据:
-
需要单个结果? → 使用
Future。 -
需要持续更新? → 使用
Stream。
-
掌握二者差异并合理运用,可显著提升 Flutter 应用的响应速度和代码可维护性。在实际开发中,常结合 Future 处理单次请求,用 Stream 管理状态(如 Bloc 库)或实时数据流,以实现高效异步编程。
相关推荐
Flutter Isolate入门指南:轻松实现高效并发编程-CSDN博客文章浏览阅读1k次,点赞30次,收藏30次。在Flutter开发中,面对复杂的业务逻辑和大量的数据处理需求,如何确保应用的流畅性和响应速度成为了开发者们关注的焦点。Flutter Isolate作为一种轻量级的并发执行单元,为我们提供了解决这一问题的有效手段。本文将带你深入了解Flutter Isolate的基本概念、使用场景以及如何在Flutter项目中轻松实现高效并发编程。_flutter isolatehttps://shuaici.blog.csdn.net/article/details/145505453Dart 中的Mixin:提高代码重用性和模块化的利器-CSDN博客文章浏览阅读1k次,点赞22次,收藏19次。本文介绍了Dart中Mixin的概念和使用方法。Mixin是一种代码重用机制,允许开发者将一些功能混入到一个类中,而不必通过继承来实现。文章详细阐述了Mixin的定义、使用以及与继承的冲突处理。通过使用Mixin,开发者可以大大提高代码的可重用性和模块化程度,将共通的功能封装起来,在需要的地方引入,避免了重复编写相同的代码。同时,Mixin还可以将复杂的代码逻辑拆分成更小的、可管理的模块,降低了代码的复杂性,提高了代码的可读性和可维护性。
https://shuaici.blog.csdn.net/article/details/145332099
正在参与 2024 博客之星评选活动,希望大佬们多多支持,谢谢啦:
https://www.csdn.net/blogstar2024/detail/070
相关文章:
Flutter 异步编程利器:Future 与 Stream 深度解析
目录 一、Future:处理单次异步操作 1. 概念解读 2. 使用场景 3. 基本用法 3.1 创建 Future 3.2 使用 then 消费 Future 3.3 特性 二、Stream:处理连续异步事件流 1. 概念解读 2. 使用场景 3. 基本用法 3.1 创建 Stream 3.2 监听 Stream 3.…...
Java短信验证功能简单使用
注册登录阿里云官网:https://www.aliyun.com/ 搜索短信服务 自己一步步申请就可以了 开发文档: https://next.api.aliyun.com/api-tools/sdk/Dysmsapi?version2017-05-25&languagejava-tea&tabprimer-doc 1.引入依赖 <dependency>…...
React进阶之React核心源码解析(一)
React核心源码解析 react 特点CPU卡顿IO 卡顿 新老 react 架构对比v15v16.8Scheduler 调度器Reconciler 协调器 React fiber原理更新dommount 构建过程 render阶段 — scheduler reconcilerreact源码解析react-domreact-dom/src/client/ReactDOMRoot.js react-reconcilerreact-…...
【Vue】打包vue3+vite项目发布到github page的完整过程
文章目录 第一步:打包第二步:github仓库设置第三步:安装插件gh-pages第四步:两个配置第五步:上传github其他问题1. 路由2.待补充 参考文章: 环境: vue3vite windows11(使用终端即可&…...
类加载机制及双亲委派模型
一、引言 二、类加载流程 1. 加载 2. 连接 2.1 验证 2.2 准备 2.3 解析 3. 初始化 三、类加载器 类加载器的类型 双亲委派模型 打破双亲委派模型 双亲委派模型优点 一、引言 在 Java 的运行机制中,类加载是一个至关重要的环节。它不仅决定了 Java 程序的动态…...
tcp/ip协议设置参数,tcp/ip协议6设置
TCP/IP协议设置参数主要涉及到IP地址、子网掩码、网关地址以及DNS服务器地址等关键参数。这些参数的配置确保了网络设备能够正确地接入互联网并与其他设备进行通信。以下是对这些参数设置的详细说明: 1. IP地址 定义:IP地址是互联网中用于唯一标识每一…...
如何在Java EE中使用标签库?
在Java EE(现在称为Jakarta EE)中使用标签库(Tag Library),主要是通过JSP标准标签库(JSTL)或自定义标签库来实现的。标签库允许在JSP页面中使用自定义的标签,从而简化页面逻辑、增强…...
【java】方法的基本内存原理(栈和堆)
java内存主要分为栈和堆,方法相关的部分主要在栈内存里,每个方法调用时会在栈里创建一个栈帧,存放局部变量和方法执行的信息。执行完后栈帧被销毁,局部变量消失。而对象实例存在堆里,由垃圾回收器管理。 **Java方法内…...
今日AI和商界事件(2025-02-15)
根据2025年2月15日的科技动态,以下是今日AI领域的重要事件及相关进展总结: 1. DeepSeek日活突破3000万,开源生态加速AI普惠 里程碑意义:开源大模型DeepSeek宣布日活跃用户数突破3000万,其R1模型凭借开源策略和低成本优…...
尚硅谷课程【笔记】——大数据之Hadoop【一】
课程视频链接:尚硅谷Hadoop3.x教程 一、大数据概论 1)大数据概念 大数据(Big Data):指无法再一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发…...
SQL 建表语句详解
SQL 建表语句详解 在 SQL 中,创建表(Table)是数据库设计的基础。表是存储数据的基本单位,每个表由行和列组成。创建表的过程涉及到定义表的结构,包括列名、数据类型、约束等。本文将详细介绍 SQL 中的建表语句&#x…...
wordpress主题插件开发中高频使用的38个函数
核心模板函数 get_header()/get_footer()/get_sidebar() – 加载模板部件 the_title()/the_content()/the_excerpt() – 显示文章标题、内容、摘要 the_post() – 循环中获取文章数据 bloginfo(‘url’) – 获取站点URL wp_head()/wp_footer() – 输出头部/尾部代码 wp_n…...
DockerFile优化镜像体积
title: DockerFile优化镜像体积 date: 2025-02-15 15:22:40 tags: DockerFile优化镜像体积DockerFile优化镜像体积 DockerFile优化镜像体积前文回顾:一、细数优化镜像体积的思路与方式二、优化Dockfile文件编辑 Dockerfile2文件三、构建镜像四、运行镜像五、查看运行效果原文 …...
使用 playwright 自定义 js 下载的路径和文件名
遇到一个问题,点击按钮自动下载文件,路径和文件名都不能自定义,可以用 playwright 来解决这个问题 from playwright.sync_api import sync_playwright import os import time class ExcelDownloader: def __init__(self, download_pat…...
Open FPV VTX开源之OSD使用分类
Open FPV VTX开源之OSD使用分类 1. 源由2. 硬件2.1 【天空端】SigmaStar2.2 【天空端】Raspberry Pi2.3 【地面端】 3. 软件3.1 天空端软件3.2 地面端软件 4. 分类4.1 嵌入式OSD分类A1-嵌入式OSD:SigmaStar Android分类A2-嵌入式OSD:SigmaStar Hi3536分…...
题解:洛谷 P4113 [HEOI2012] 采花
题目https://www.luogu.com.cn/problem/P4113 运用类似于P1972 [SDOI2009] HH的项链的操作,将数据离线下来处理。 按照区间右端点从小到大排序。 问题是数量大于等于 的时候才能算进去。 于是乎我们用两个数组维护倒数第二次出现和最后一次出现的地方。 每次在…...
linux概念详解
用户守护进程 用户空间守护进程是一些在后台运行的长期服务程序,提供系统级服务。 下面举一些例子。 网络服务: 如sshd(SSH服务)、httpd(HTTP服务)。 sshd:sshd 守护进程会在后台运行&#x…...
easyexcel快速使用
1.easyexcel EasyExcel是一个基于ava的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel 即通过java完成对excel的读写操作, 上传下载 2.easyexcel写操作 把java类中的对象写入到excel表格中 步骤 1.引入依赖 <depen…...
fetch() 与 XMLHttpRequest 的差异
fetch() 与 XMLHttpRequest 的差异 fetch() 的功能与 XMLHttpRequest 基本相同,都是向服务器发出 HTTP 请求,但有三个主要的差异。 (1)fetch()使用 Promise,不使用回调函数,因此大大简化了写法࿰…...
【java面向对象的三大特性】封装、继承和多态
目录标题 一、封装(Encapsulation):二、继承(Inheritance):三、多态(Polymorphism):1. 多态的三个必要条件:2.多态的具体实现:3.多态的使用场景&a…...
c# textbox 设置不获取光标
[DllImport("user32",EntryPoint "HideCaret")] private static extern bool HideCaret(IntPtr hWnd); //需引入命名空间using System.Runtime.InteropServices; private void Txt_RecInfo_MouseDown(object sender, MouseEventArgs e) { …...
算法13-BFPRT算法
一、BFPRT 算法概念 BFPRT 算法(Blum-Floyd-Pratt-Rivest-Tarjan 算法)是一种用于在无序数组中快速找到第 k 小(或第 k 大)元素的高效算法。它的时间复杂度为 O(n),在最坏情况下也能保证线性时间复杂度。BFPRT 算法的…...
android studio下载安装汉化-Flutter安装
1、下载android studio官方地址:(这个网址可能直接打不开,需要VPN) https://developer.android.com/studio?hlzh-cn mac版本分为X86和arm版本,电脑显示芯片是Inter的就是x86的,显示m1和m2的就是arm的 …...
Seaweedfs(master volume filer) docker run参数帮助文档
文章目录 进入容器后执行获取weed -h英文中文 weed server -h英文中文 weed volume -h英文中文 关键点测试了一下,这个-volume.minFreeSpace string有点狠,比如设置值为10(10%),它直接给系统只留下10%的空间࿰…...
嵌套调用实现数组元素逆序存放
主函数调用reverse_array(int ptr[],int cnt)函数,该函数在调用inplace_swap(int *x,int *y)函数时,把两个不同的地址送给inplace_swap(int *x,int *y)函数,实现这两个位置处元素的交换。 令*xa,*yb 则*y *x^*y执行后,*xa,*ya^b…...
【工业安全】-CVE-2022-35555- Tenda W6路由器 命令注入漏洞
文章目录 1.漏洞描述 2.环境搭建 3.漏洞复现 4.漏洞分析 4.1:代码分析 4.2:流量分析 5.poc代码: 1.漏洞描述 漏洞编号:CVE-2022-35555 漏洞名称:Tenda W6 命令注入 威胁等级:高危 漏洞详情࿱…...
Spark 和 Flink
Spark 和 Flink 都是目前流行的大数据处理引擎,但它们在架构设计、应用场景、性能和生态方面有较大区别。以下是详细对比: 1. 架构与核心概念 方面Apache SparkApache Flink计算模型微批(Micro-Batch)为主,但支持结构…...
Jupyter lab 无法导出格式 Save and Export Notebook As无法展开
本来尝试jypyter lab如何导出HTML带有侧边导航栏,一顿操作后发现还是没实现。 又突然发现导出其他格式地功能不能用了,浏览器里Save and Export Notebook As展开按钮为灰色打不开。 经典想实现的没实现还把原先的搞坏了。 看了jupyter lab的运行信息发…...
C#(Winform)通过添加AForge添加并使用系统摄像机
先展示效果 AForge介绍 AForge是一个专门为开发者和研究者基于C#框架设计的, 也是NET平台下的开源计算机视觉和人工智能库 它提供了许多常用的图像处理和视频处理算法、机器学习和神经网络模型,并且具有高效、易用、稳定等特点。 AForge主要包括: 计算机视觉与人…...
【LeetCode: 611. 有效三角形的个数 + 排序 + 双指针】
🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…...
