当前位置: 首页 > news >正文

Flutter 异步编程:Future 与 Stream 深度解析

 系列入口:


1️⃣ Future 与 Stream 深度解析 
2️⃣Isolate 与 compute 性能优化
3️⃣ FutureBuilder 与 StreamBuilder 架构优化
4️⃣ 异步 + 状态管理融合(Riverpod / Bloc)
5️⃣ Flutter 响应式架构设计
欢迎留言 👍 点个 关注 ❤️,不错过后续更新!
 

引言

在 Flutter 开发中,异步编程无处不在——从网络请求到动画控制、文件读写到 Socket 通信。
而支撑这一切的核心机制,就是 Future 与 Stream。

本文将结合项目实战,从原理到最佳实践,一次性搞懂 Flutter 的异步体系。

一、为什么 Flutter 需要异步?

Flutter 采用 单线程 UI 渲染模型
主 Isolate 负责所有渲染与事件响应,如果执行耗时任务(如 I/O 或 JSON 解析)会造成 UI 卡顿。

异步编程的意义:让程序在“等待”的同时继续渲染界面。

void fetchData() {final data = http.get('https://api.example.com/user');print('请求已发送');
}

这时 print 会先执行,因为 Dart 的事件循环会让 Future 异步排队执行。

二、Future:一次性异步任务

Future 表示一个将来会返回结果的异步操作。它可以成功、失败或超时。

Future<String> getUserName() async {await Future.delayed(const Duration(seconds: 2));return 'FlutterDev';
}void main() async {print('开始');final name = await getUserName();print('你好,$name');
}

输出:

开始
(等待2秒)
你好,FlutterDev

三、async / await 实战与最佳实践

1. async + await 原理速记

  • async 把函数变成异步函数,返回 Future<T>

  • await 会暂停当前函数直到该 Future 完成;

  • await 后续代码会被放入 microtask 队列,优先执行。

Future<User> fetchUser() async {final res = await http.get(Uri.parse('https://api.xxx.com/user'));return User.fromJson(json.decode(res.body));
}

2. 串行 vs 并行

// 串行(前一步结果是后一步输入)
final token = await login();
final profile = await fetchProfile(token);// 并行(互不依赖)
final result = await Future.wait([apiA(), apiB(), apiC()]);

3. 错误与超时

try {final data = await fetch();
} on TimeoutException {print('请求超时');
} catch (e, st) {print('异常: $e');
}

4. 重试与竞速

Future<T> retry<T>(Future<T> Function() run, {int max = 3}) async {var delay = const Duration(milliseconds: 300);for (int i = 0; i < max; i++) {try { return await run(); } catch (_) {}await Future.delayed(delay);delay *= 2; // 指数退避}return await run();
}// 竞速:谁先返回用谁
final fastest = await Future.any([pingA(), pingB()]);

5. UI绑定:FutureBuilder

FutureBuilder<User>(future: fetchUser(),builder: (_, snap) {if (snap.connectionState == ConnectionState.waiting) {return const CircularProgressIndicator();}if (snap.hasError) return Text('错误:${snap.error}');return Text('Hi, ${snap.data!.name}');},
);

6. 异步取消

Dart 的 Future 无法直接取消,可用软标志:

bool _canceled = false;
Future<void> runJob() async {_canceled = false;final a = await step1();if (_canceled) return;final b = await step2(a);
}
void cancelJob() => _canceled = true;

或使用 CancelableOperation(来自 package:async)。

7. 小结口诀

有依赖 → 串行;无依赖 → 并行;
操作UI前先判断 mounted
超时、重试、竞速都靠 Future 组合。

四、Stream:持续事件的流

Stream 用于处理多次异步事件,如进度更新、传感器、Socket。

final controller = StreamController<int>();controller.stream.listen((event) => print('收到:$event'),onError: (e) => print('错误:$e'),onDone: () => print('结束'),
);controller.add(1);
controller.add(2);
controller.close();

输出:

收到:1
收到:2
结束
 

常见应用场景

场景示例
下载/上传进度Stream<double>
蓝牙 / 串口数据Stream<List<int>>
用户输入防抖debounce
Socket 长连接Stream<String>

五、Future vs Stream 对比

特性FutureStream
结果数量一次多次
典型场景网络请求进度/Socket
取消支持可取消订阅
UI绑定组件FutureBuilderStreamBuilder

六、Event Loop 与微任务机制

Dart 异步执行顺序:

microtask → event → render → 下一帧
 

示例:

print('A');
scheduleMicrotask(() => print('B'));
Future(() => print('C'));
print('D');
// 输出: A, D, B, C

七、实战案例:下载进度条

class DownloadTask {final _ctrl = StreamController<double>();Stream<double> get progress => _ctrl.stream;Future<void> start() async {for (int i = 1; i <= 10; i++) {await Future.delayed(const Duration(milliseconds: 500));_ctrl.add(i / 10);}_ctrl.close();}
}final task = DownloadTask();task.progress.listen((p) => print('进度: ${(p * 100).toInt()}%'));
task.start();

八、异步任务选型决策表

场景推荐方案
一次性请求(接口 / 文件)Future + async/await
多次更新(进度 / 实时数据)Stream
并发请求Future.wait / Future.any
可取消任务CancelableOperation
大计算任务compute / Isolate
UI绑定FutureBuilder / StreamBuilder

九、总结

  • Future:一次性异步操作;

  • Stream:多次事件流;

  • async/await:让异步像同步;

  • Event Loop:协调调度顺序;

  • 搭配 FutureBuilder 与 StreamBuilder
    就能构建不卡顿、响应流畅的 Flutter 界面。

http://www.dtcms.com/a/527963.html

相关文章:

  • 代码训练LeetCode(48)字母异位词分组
  • 每日算法刷题Day79:10.25:leetcode 一般树5道题,用时1h30min
  • 数据分析核心术语略解
  • 南宁网站设计和开发大赛诚信通开了网站谁给做
  • MATLAB基于云模型时间序列预测
  • 【成长纪实】HarmonyOS Next学习地图:新手避坑指南与核心知识点拆解
  • wordpress不适合大型网站网站建设对宣传的意义
  • 大良营销网站建设教程写网站建设需求文档
  • CICD实战(13) - 使用Arbess+GitLab实现.Net core项目自动化部署
  • KingbaseES赋能多院区医院信创转型:浙江省人民医院异构多活数据底座实践解析
  • 微硕WSF2N65 650V N沟MOSFET:汽车PTC辅助加热器“高压启动核”
  • 如何在Mac进行Safari网页长截图?
  • 【2026计算机毕业设计】基于Jsp的汽车租赁信息管理系统
  • LLMs之PE:PromptX(将 AI 智能体从通用助手转变为具备行业/角色能力的交互平台)的简介、安装和使用方法、案例应用之详细攻略
  • AI驱动的DevOps:AI大模型自动化部署、监控和运维流程
  • 汽车销售|汽车推荐|基于SprinBoot+vue的新能源汽车个性化推荐系统(源码+数据库+文档)
  • 佳易王试用版汽车保养维修服务记录查询系统 V17.1:提升汽修门店管理效率的实用工具#汽修保养
  • 我的firefox的新建标签+按钮找不到了
  • 网站建设方案 下载开个网站需要什么
  • 揭阳网站建设维护网站建设 教程
  • HTTP方法的安全性和幂等性
  • HTTP、HTTPS 和 WebSocket 协议和开发
  • 动态规划详细题解——力扣198.打家劫舍
  • 【LeetCode热题100(52/100)】课程表
  • 什么行业必须做网站棋牌软件开发一个多少钱
  • LeetCode:698. 划分为k个相等的子集
  • 【LeetCode100】--- 101.重排链表【思维导图+复习回顾】
  • 【C++:继承】C++面向对象继承全面解析:派生类构造、多继承、菱形虚拟继承与设计模式实践
  • LeetCode 面试经典 150_链表_反转链表 II(60_92_C++_中等)(头插法)
  • 第 08 天:编辑器和终端快捷键 (nano, vi/vim)