Flutter 异步深度吃透:Future、Stream 核心原理
一、前言:为什么必须吃透 Future & Stream?
Dart 是单线程事件循环模型,所有耗时操作(网络请求、本地IO、蓝牙通信、定时任务)都不能阻塞 UI 主线程,异步编程是 Flutter 开发的核心基石。
绝大多数 Flutter 开发者的异步困惑,根源是分不清两个核心概念:
-
Future:单次异步任务,一次执行、一次结果、即刻结束
-
Stream:持续异步数据流,持续监听、多次推送、可无限流转
简单通俗类比:
-
Future:点外卖,下单后只送达一次,任务结束
-
Stream:实时直播,持续不断推送画面,可随时观看、随时关闭
本文从零拆解两者底层原理、语法用法、进阶技巧、场景差异,搭配超多极简可运行代码示例,结合 Flutter 专属的 FutureBuilder、StreamBuilder 实战,彻底搞定 Flutter 异步开发。
二、Future 全方位详解(单次异步)
1. Future 核心特性
-
生命周期:等待中(Pending)→ 成功(Resolved)/ 失败(Rejected)
-
仅返回 一个结果,任务完成即销毁
-
用于一次性耗时操作:网络请求、文件读取、单次数据库查询
2. Future 基础用法示例(3种写法)
写法1:原始 then / catchError 链式调用
// 模拟网络请求耗时任务
Future<String> requestData() {
return Future.delayed(const Duration(seconds: 2), () {
// 模拟请求成功
return "接口数据请求成功:用户信息";
// 模拟请求异常
// throw Exception("网络请求失败");
});
}
void main() {
print("开始请求数据");
requestData().then((res) {
print("结果:$res");
}).catchError((err) {
print("异常:$err");
}).whenComplete(() {
print("任务结束,无论成功失败都会执行");
});
}
写法2:async / await(推荐,代码同步化)
async/await 是 Future 的语法糖,彻底告别地狱回调,代码可读性极强。
Future<void> asyncRequest() async {
print("开始异步请求");
try {
String res = await requestData();
print("结果:$res");
} catch (e) {
print("异常捕获:$e");
} finally {
print("任务最终完成");
}
}
// 调用
// asyncRequest();
写法3:Future 立即执行/延迟执行
// 立即执行并返回成功结果
Future.value("直接成功数据");
// 立即抛出异常
Future.error(Exception("主动抛出异常"));
// 延迟执行
Future.delayed(const Duration(seconds: 1), () => print("1秒后执行"));
3. Future 进阶实战:串行/并行执行
场景1:串行执行(A执行完再执行B)
适用于依赖型任务:先获取 token,再请求接口
// 任务1:获取Token
Future<String> getToken() async {
await Future.delayed(const Duration(seconds: 1));
return "TOKEN_123456";
}
// 任务2:携带Token请求数据
Future<String> getUserInfo(String token) async {
await Future.delayed(const Duration(seconds: 1));
return "用户数据(Token:$token)";
}
// 串行调用
Future<void> serialTask() async {
String token = await getToken();
String userInfo = await getUserInfo(token);
print(userInfo);
}
场景2:并行执行(A、B同时执行,节省时间)
使用 Future.wait,适用于无依赖的多个异步任务,大幅提升效率
// 并行执行多个耗时任务
Future<void> parallelTask() async {
// 同时开启两个任务
List<String> results = await Future.wait([
getToken(),
requestData(),
]);
print("任务1结果:${results[0]}");
print("任务2结果:${results[1]}");
}
串行总耗时≈2s,并行总耗时≈1s,性能提升一倍。
4. Flutter 页面实战:FutureBuilder
专门适配 Future 异步 UI,无需手动 setState,自动监听 Future 状态刷新界面。
import 'package:flutter/material.dart';
class FutureBuilderDemo extends StatelessWidget {
const FutureBuilderDemo({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<String>(
future: requestData(),
builder: (context, snapshot) {
// 加载中
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
// 加载失败
if (snapshot.hasError) {
return Center(child: Text("请求失败:${snapshot.error}"));
}
// 加载成功
if (snapshot.hasData) {
return Center(child: Text("数据:${snapshot.data}"));
}
return const SizedBox();
},
),
);
}
}
三、Stream 全方位详解(持续数据流)
1. Stream 核心特性
-
持续产生数据:零次、一次、多次数据推送
-
可监听、可暂停、可取消、可关闭
-
用于持续性数据流场景:蓝牙广播、实时日志、下载进度、定时器、WebSocket 消息
核心关键词:异步流、持续推送、响应式
2. Stream 基础创建方式(4种常用示例)
方式1:async* + yield 生成流(最常用)
async* 标识流式异步,yield 持续推送数据(区别于 Future 的 return)
// 每秒推送一个数字,共5次
Stream<int> countDownStream() async* {
for (int i = 5; i > 0; i--) {
await Future.delayed(const Duration(seconds: 1));
yield i; // 持续推送数据
}
}
// 监听流数据
void listenStream() {
countDownStream().listen((value) {
print("当前数值:$value");
}, onError: (err) {
print("流异常:$err");
}, onDone: () {
print("数据流传输完成");
});
}
方式2:StreamController 手动管控流(业务高频)
手动 add 数据、关闭流,灵活适配蓝牙、进度条等动态场景
import 'dart:async';
class StreamDemo {
// 初始化流控制器
final StreamController<double> _progressCtrl = StreamController();
// 暴露流
Stream<double> get progressStream => _progressCtrl.stream;
// 模拟下载进度推送
void startDownload() {
double progress = 0;
Timer.periodic(const Duration(milliseconds: 200), (timer) {
progress += 0.1;
if (progress >= 1) {
timer.cancel();
_progressCtrl.close(); // 关闭流
}
_progressCtrl.add(progress); // 推送进度数据
});
}
}
方式3:Stream 内置快速构造器
// 1. 从集合生成流
Stream.fromIterable([1, 2, 3, 4, 5]).listen(print);
// 2. 定时生成流(每秒推送,只取前5个)
Stream.periodic(const Duration(seconds: 1), (idx) => idx)
.take(5)
.listen(print);
// 3. 单次数据流
Stream.value("单次流数据");
3. Stream 核心进阶操作(过滤、转换、合并)
Stream 支持丰富的链式操作,无需手动遍历,极简处理数据流
Stream<int> numStream() async* {
for (int i = 1; i <= 10; i++) {
await Future.delayed(const Duration(milliseconds: 300));
yield i;
}
}
void streamOperator() {
numStream()
.where((value) => value % 2 == 0) // 过滤:只保留偶数
.map((value) => value * 10) // 转换:数值*10
.take(3) // 截取前3个数据
.listen((res) {
print("处理后数据:$res");
});
// 输出:20 40 60
}
4. 单订阅流 vs 多订阅流(高频坑点)
-
单订阅流(默认):只能被监听一次,重复监听直接报错(async*、StreamController 默认)
-
多订阅流(广播流):支持多处同时监听,适配全局状态、多组件订阅场景
// 转为广播流,支持多监听
void broadcastStream() {
var stream = countDownStream().asBroadcastStream();
// 监听1
stream.listen((v) => print("监听1:$v"));
// 监听2
stream.listen((v) => print("监听2:$v"));
}
5. Flutter 页面实战:StreamBuilder
适配持续数据流 UI:下载进度、蓝牙状态、实时计数、弹幕等,自动响应数据更新
class StreamBuilderDemo extends StatefulWidget {
const StreamBuilderDemo({super.key});
@override
State<StreamBuilderDemo> createState() => _StreamBuilderDemoState();
}
class _StreamBuilderDemoState extends State<StreamBuilderDemo> {
final StreamDemo _demo = StreamDemo();
@override
void initState() {
super.initState();
_demo.startDownload();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder<double>(
stream: _demo.progressStream,
initialData: 0.0,
builder: (context, snapshot) {
double progress = snapshot.data ?? 0;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LinearProgressIndicator(value: progress),
const SizedBox(height: 20),
Text("下载进度:${(progress * 100).toStringAsFixed(0)}%"),
],
);
},
),
),
);
}
@override
void dispose() {
_demo._progressCtrl.close(); // 页面销毁关闭流,防内存泄漏
super.dispose();
}
}
四、Future vs Stream 核心区别(一张表彻底分清)
|
对比维度 |
Future |
Stream |
|---|---|---|
|
数据次数 |
单次结果,一次完成 |
多次持续推送,流式输出 |
|
生命周期 |
完成/报错即结束 |
可持续运行,手动关闭销毁 |
|
核心关键字 |
async、await、return |
async*、yield、listen、controller |
|
UI 组件 |
FutureBuilder |
StreamBuilder |
|
典型场景 |
接口请求、文件读取、单次IO |
蓝牙广播、进度条、WebSocket、实时状态 |
|
资源消耗 |
低,自动释放 |
较高,需手动关闭防泄漏 |
五、高频实战场景选型指南
优先用 Future 的场景
-
单次网络 GET/POST 请求
-
本地文件读写、SP 存储读取
-
单次数据库查询、新增、修改
-
一次性弹窗异步校验、授权请求
优先用 Stream 的场景
-
BLE 蓝牙持续扫描、设备状态监听
-
文件下载/上传实时进度监听
-
WebSocket、MQTT 实时消息推送
-
实时计时器、计数器、日志打印
-
全局状态订阅、多组件实时同步数据
六、高频坑点与避坑方案
Future 避坑
-
忘记异常捕获:async/await 必须搭配 try/catch,否则异常崩溃
-
滥用串行执行:无依赖任务不用 await 串行,改用 Future.wait 并行提速
-
FutureBuilder 重复请求:build 重建会重复触发 Future,需在 State 中缓存 Future 实例
Stream 避坑
-
流未关闭导致内存泄漏:页面销毁必须 close StreamController、取消监听
-
单流多监听报错:多组件订阅务必转为 broadcast 广播流
-
无限流死循环:定时/循环流必须设置终止条件,避免后台无限推送
-
未处理异常:listen 必须配置 onError,防止流异常导致页面崩溃
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)