前言
想象这样一个场景:你在外卖App
下单后,界面突然卡住不动,直到30
分钟后才显示送达 —— 这种体验绝对会让用户抓狂。现实中,手机App
之所以能流畅运行,正是因为处理了类似的"等待"
问题。
在Flutter
中,Future
就是解决这类异步任务的核心工具。它像一位高效的快递调度员,让你的程序在等待网络请求
、文件读写
时保持丝滑响应。
本文将用最贴近生活的案例,带你系统掌握Future
的核心原理、常见坑点和企业级应用场景,彻底告别"转圈焦虑"
!
操千曲而后晓声,观千剑而后识器。虐它千百遍方能通晓其真意。
一、基本概念
graph TD
A[Future] --> B[三大状态]
A --> C[设计哲学]
B --> B1[Pending]
B --> B2[Resolved]
B --> B3[Rejected]
C --> C1[不阻塞主线程]
C --> C2[异步结果承诺]
官方定义:Future
表示一个可能还没有完成
的异步操作
的结果
。
- 可能还没完成 :说明操作具有
延迟性
,就像网购包裹可能在运输中。 - 异步操作 :强调执行过程不会阻塞主线程(
UI线程
)。 - 结果 :最终会产出两种确定性状态 —— 成功(
包含数据
)或失败(携带异常
)。
通俗理解:
假设你订了外卖(发起网络请求
),这时你有两个选择:
- 1、傻站在门口等骑手(
同步阻塞,界面卡死
)。 - 2、留下地址继续追剧,骑手到了按门铃(
异步非阻塞
)。
Future
就是那个"门铃通知机制"
。它不会阻塞你的主线程(追剧
),当异步任务(外卖
)完成后,通过回调函数(门铃响
)通知你结果。
核心特征:
- 状态机:
未完成
→已完成(成功/失败)
。- 单次性:一个
Future
只能完成一次(像一次性门票
)。
二、核心价值
2.1、突破单线程枷锁
的生存法则
Flutter
应用运行在Dart
的单线程模型上,就像只有一个服务员的餐厅。如果服务员必须等牛排煎熟(耗时操作
)才能服务其他客人(处理点击事件
),整个餐厅就会瘫痪。Future
通过"异步排队机制"
解决了这个根本矛盾:
// ❌错误示范:点击按钮后整个界面冻结3秒
ElevatedButton(
onPressed: () {
sleep(Duration(seconds:3)); // 同步休眠
showDialog(...);
}
)
// ✅正确做法:点击后界面仍然可操作
ElevatedButton(
onPressed: () {
Future.delayed(Duration(seconds:3), () {
showDialog(...);
});
}
)
底层原理:
事件循环(
Event Loop
)像智能调度员,将Future
任务放入"任务队列"
,主线程在处理完每一帧的UI
渲染后,才会从队列中取出任务执行,保证60FPS
的流畅体验。
2.2、Future
存在的必要性
异步操作的不可或缺性:
功能场景 | 平均耗时 | 使用Future 必要性 |
---|---|---|
网络请求 | 1-5s | ⭐⭐⭐⭐⭐ |
本地数据库查询 | 200-500ms | ⭐⭐⭐⭐ |
图片压缩 | 300-800ms | ⭐⭐⭐⭐ |
传感器数据采集 | 持续获取 | ⭐⭐⭐⭐⭐ |
真实案例对比:
- 淘宝
APP
首页:同时发起20+
个异步请求(商品推荐、用户信息、活动数据...)。 - 微信聊天界面:需要并行处理消息接收(
Stream
)和图片上传(Future
)。
2.3、从"回调地狱"
到"代码天堂"
的进化史
回调地狱版:
login((user) {
getProfile(user.id, (profile) {
getOrders(profile.level, (orders) {
updateUI(orders, () {
log("完成!", (result) {
// 更多嵌套...
});
});
});
});
});
Future
链式调用版:
login()
.then((user) => getProfile(user.id))
.then((profile) => getOrders(profile.level))
.then((orders) => updateUI(orders))
.then((_) => log("完成!"))
.catchError(handleError);
async/await
终极版(同步写法异步效果
):
try {
final user = await login();
final profile = await getProfile(user.id);
final orders = await getOrders(profile.level);
await updateUI(orders);
await log("完成!");
} catch (e) {
handleError(e);
}
2.4、错误处理的安全网体系
对比传统try-catch
的局限性,Future
提供全方位防护:
// 传统方式可能遗漏的错误点
void fetchData() {
try {
http.get(url).then((response) {
// 这里发生的错误不会被外层catch
});
} catch (e) {
// 只能捕获同步错误
}
}
// Future的完整错误链
fetchData()
.then(parseJSON) // 步骤1
.then(validateData) // 步骤2
.then(updateCache) // 步骤3
.catchError((e) { // 统一捕获所有环节错误
showErrorToast(e);
});
错误穿透机制:任何一个环节抛出异常,都会跳过后续的
then
,直接触发最近的catchError
,类似电路中的保险丝熔断机制。
三、属性本质解析
Future
没有直接暴露的公共属性,但其内部状态通过三个维度
体现:
-
Pending
(等待态):- 表征:任务已创建但尚
未执行/未完成
。 - 检测方式:未触发任何回调时默认状态。
- 表征:任务已创建但尚
-
Completed
(完成态):- 成功子态:通过
then()
回调传递结果值。 - 失败子态:通过
catchError()
传递异常对象。 - 检测方式:通过
回调触发
顺序判断。
- 成功子态:通过
状态追踪:
future.isCompleted
:判断任务是否完成。future.asStream()
:将一次性结果转为流式监听(适合多次监听场景)。
四、核心方法深入剖析
4.1、静态工厂方法:第一梯队
①、Future(FutureOr<T> computation())
:工厂构造函数详解
factory Future(FutureOr<T> computation()) {
// 1. 创建未完成的 _Future 实例
_Future<T> result = new _Future<T>();
// 2. 调度异步执行
Timer.run(() {
FutureOr<T> computationResult;
try {
// 3. 执行用户代码
computationResult = computation();
} catch (e, s) {
// 4. 同步错误处理
_completeWithErrorCallback(result, e, s);
return;
}
// 5. 结果处理
result._complete(computationResult);
});
return result;
}
此工厂构造函数用于创建并调度一个异步任务,其内部执行流程如下:
-
1、创建
_Future
实例
初始化一个_Future<T>
对象,状态为Pending
,表示任务尚未完成。 -
2、异步调度
通过Timer.run()
将computation
回调加入 事件队列,确保其不会立即执行,而是等待当前同步代码
和微任务队列
清空后执行。 -
3、执行
computation
函数
在事件循环中执行回调:- 同步错误捕获:若
computation
抛出同步错误(如throw Exception()
),立即通过_completeWithErrorCallback
将错误传递给_Future
对象。 - 返回值处理:若
computation
返回普通值或Future<T>
,调用_complete
方法处理结果。
- 同步错误捕获:若
-
4、结果传递
_complete
方法智能处理返回值:- 普通值:直接标记
_Future
为完成状态(Resolved
),触发then
回调。 - 嵌套
Future
:等待内部Future
完成,将其结果/错误传播到外层Future
,形成链式响应。
- 普通值:直接标记
关键设计思想:
-
1、
Timer.run()
的作用:异步边界控制
强制建立异步边界,即使computation
是同步代码(如返回普通值
),也保证Future
的异步性。print("Start"); Future(() => print("Async Task")); print("End"); // 输出顺序:Start → End → Async Task
-
2、
FutureOr<T>
的兼容性:灵活的结果处理
允许computation
返回同步值或异步Future
,统一处理逻辑:// 同步返回 Future(() => 42).then(print); // 输出42 // 异步返回 Future(() => Future.delayed(Duration(seconds:1), () => 100)) .then(print); // 1秒后输出100
-
3、错误传播机制
- 同步错误:通过
try-catch
直接捕获,标记Future
为失败状态。 - 异步错误:若
computation
返回的Future
失败,错误会通过_complete
递归传递到外层Future
:
Future(() => Future.error(Exception("Error"))) .catchError(print); // 捕获异常
- 同步错误:通过
②、Future.delayed()
:延时任务调度器
作用:创建延迟指定时间后执行的异步任务。
典型场景:
// 延时显示加载动画
Future.delayed(Duration(milliseconds: 200), () {
if (!isLoaded) showLoading();
});
// 模拟网络请求
Future<String> mockApiCall() {
return Future.delayed(
Duration(seconds: 2),
() => '{"status": "success"}'
);
}
核心机制:
- 1、启动
Timer
计时器(底层使用事件循环
)。 - 2、计时结束后将任务加入事件队列。
重要注意事项:
- 不会取消:即使
Future
被丢弃,Timer
仍会触发。 - 精确性问题:实际延迟可能略大于指定时间(
受事件循环影响
)。 - 空回调处理:
// 正确的空操作写法 Future.delayed(Duration(seconds: 1)); // computation 参数可省略
③、Future.value()
:即时值包装器
作用:将现有值包装为已完成的成功状态的Future
。
机制:即将值存入Future
的完成状态,同步触发 then()
回调(下一个微任务周期前执行
)。
典型场景:
// 缓存优先策略
Future<String> fetchData(bool useCache) {
return useCache
? Future.value(cachedData) // 同步返回缓存
: http.get(url); // 异步网络请求
}
注意事项:如果不需要异步特性,直接使用同步值。
// ❌ 错误:创建不必要的 Future 对象
Future.value(1).then((v) => print(v));
// ✅ 正确:直接同步处理
final result = syncCalculate();
④、Future.error()
:错误生成器
作用:创建立即失败的 Future
,携带错误信息
。
企业级实战:
Future<double> calculateBMI(double weight, double height) {
if (height <= 0) {
return Future.error(
ArgumentError('身高必须大于0'),
StackTrace.current // 携带堆栈信息
);
}
return Future.value(weight / (height * height));
}
错误处理建议:自定义异常类型(继承 Exception
),并附加调试信息:
class NetworkException implements Exception {
final int code;
final String message;
NetworkException(this.code, this.message);
}
Future.error(NetworkException(500, "服务不可用"));
⑤、Future.microtask()
:微任务调度器
作用:将任务加入微任务队列(优先于事件队列执行)
执行优先级:主线程
→ 微任务队列
→ 事件队列
。
典型场景:
// 状态更新后立即渲染
void updateState() {
Future.microtask(() => setState(() {}));
}
// 确保代码执行顺序
print('A');
Future.microtask(() => print('B'));
Future(() => print('C'));
print('D');
// 输出顺序:A → D → B → C
注意事项:
- 微任务应保持轻量(
执行时间 < 1ms
)。 - 避免嵌套微任务导致死循环:
// ❌ 危险代码:微任务死循环 void recursiveMicrotask() { Future.microtask(() { print("无限循环"); recursiveMicrotask(); }); }
⑥、Future.sync()
:同步兼容器
作用:将同步/异步
代码统一包装为Future
。
特殊能力:
- 同步执行
computation
函数。 - 自动处理同步异常。
对比实验:
// 同步异常处理
Future.sync(() => throw Exception('错误1'))
.catchError((e) => print(e)); // 能捕获
Future(() => throw Exception('错误2'))
.catchError((e) => print(e)); // 同样能捕获
典型场景:
// 兼容同步/异步返回值
Future<Data> fetch() {
return Future.sync(() {
if (cacheValid) return cachedData; // 同步返回
return fetchFromNetwork(); // 异步操作
});
}
⑦、方法对比与选型指南
方法 | 执行时机 | 适用场景 | 性能影响 |
---|---|---|---|
Future.delayed() | 延时事件队列 | 定时任务/模拟延迟 | 依赖 Timer |
Future.value() | 立即完成 | 同步值转异步 | 无额外开销 |
Future.error() | 立即失败 | 快速抛出业务异常 | 低 |
Future.microtask() | 下一微任务周期 | 状态更新/确保执行顺序 | 需控制任务体积 |
Future.sync() | 立即执行 | 兼容同步/异步代码 | 同步执行风险 |
4.2、结果处理三剑客
:第二梯队
方法 | 作用维度 | 典型场景 |
---|---|---|
then() | 成功结果处理 | 数据处理流水线 |
catchError() | 错误捕获处理 | 异常兜底、错误日志 |
whenComplete() | 最终清理 | 关闭 Loading /释放资源 |
① .then((value){...})
:成功结果处理
Future<String> order = fetchUserData();
order.then((data) => print('收到数据:$data'));
类比:骑手打电话说"外卖放门口了"
,你决定何时去取。
② .catchError(handleError)
:失败结果处理
future.catchError((error) {
print('请求失败:$error');
showErrorDialog();
});
注意事项:必须处理异常,否则会导致程序崩溃
(如同外卖丢了却不联系商家)。
③ .whenComplete((){...})
:最终处理
无论成功/失败
都会执行,适合清理工作:
future.whenComplete(() => hideLoadingIndicator());
④ 经典组合
示例:
Future.value(10)
.then((v) => v * 2)
.catchError((e) => print("Error: $e"))
.whenComplete(() => print("Done"));
4.3、增强型控制方法:第三梯队
① timeout()
:超时熔断
// 源码
Future<T> timeout(
Duration timeLimit,
{FutureOr<T> Function()? onTimeout}
)
// 基本用法:网络请求超时降级
fetchData().timeout(
Duration(seconds: 3),
onTimeout: () => cachedData
);
-
核心机制:
- 创建监听定时器,超时后触发熔断。
- 若指定
onTimeout
,返回其生成值替代原结果。
-
注意事项:
- 原
Future
不会被取消(Dart
没有真正的中断机制)。 - 超时后仍可能收到原
Future
的结果(但会被忽略
)。
- 原
② onError()
:类型安全错误处理
// 源码
Future<T> onError<E extends Object>(
FutureOr<T> Function(E error, StackTrace stackTrace) handleError
)
// 错误!FormatException 是 IOException 的子类
.onError<IOException>((e) => ...)
// 正确写法应捕获更具体的异常
- 相比
catchError
的优势:- 编译期类型检查(
泛型约束
)。 - 可返回替代值使流程继续。
- 编译期类型检查(
4.4、高级静态方法:第四梯队
①、Future.any()
:竞速抢跑者
作用:返回首个完成的 Future
(无论成功/失败
)。
典型场景:
// 多服务器择优访问
final fastest = await Future.any([
fetchFromAWS(),
fetchFromAliCloud(),
fetchFromTencentCloud()
]);
核心机制:
- 监听所有
futures
的完成事件。 - 第一个触发完成(
成功或失败
)的Future
决定结果。 - 不会取消其他未完成的
Future
注意事项:
- 若首个完成的
Future
失败,整个any()
会抛出错误。 - 资源泄漏风险:未完成的
Future
可能继续执行。 - 安全用法:
Future.any([task1, task2]) .then(handleResult) .catchError((e) => handleFastestError(e));
②、Future.forEach()
:异步遍历器
作用:按顺序异步处理集合元素
执行流程:
元素1 → 异步处理 → 完成 → 元素2 → ...
典型场景:
// 批量上传图片
await Future.forEach(imageFiles, (file) async {
final url = await uploadToOSS(file);
await saveToDatabase(url);
});
性能陷阱:
- 顺序执行效率低(
适合有依赖关系的任务
)。 - 并行优化方案:
// 使用 Future.wait 并行执行 Future.wait(imageFiles.map(uploadToOSS));
③、Future.doWhile()
:条件循环器
作用:重复执行异步任务直到条件不满足
。
执行逻辑:
执行 action → 返回 true → 继续循环
→ 返回 false → 退出
典型用例:
// 分页加载直到数据为空
int page = 1;
await Future.doWhile(() async {
final data = await fetchPage(page++);
if (data.isEmpty) return false;
cache.addAll(data);
return true;
});
风险控制:
- 必须设置安全终止条件,避免
无限循环
. - 添加超时熔断:
Future.doWhile(() => ...) .timeout(Duration(seconds: 30));
④、Future.asStream()
:流转换器
作用:将 Future
转换为单元素 Stream
流行为:
Future
成功 → 发射数据事件 → 关闭流Future
失败 → 发射错误事件 → 关闭流
典型场景:
// 适配 StreamBuilder
Stream<File> get fileStream =>
writeFileFuture.asStream();
// 组合流处理
fileStream
.expand((file) => parseFile(file))
.listen(handleData);
重要特性:
- 即使
Future
已完成,监听时会立即发射事件。 - 多次监听会创建独立订阅:
final stream = future.asStream(); stream.listen(print); // 触发一次 stream.listen(print); // 再次触发
⑤、Future.wait()
:多任务协调器
作用:并行执行多个 Future
,统一返回结果。
// 源码
static Future<List<T>> wait<T>(
Iterable<Future<T>> futures, {
bool eagerError = false,
void Function(T successValue)? cleanUp
})
参数详解:
eagerError
:是否在首个错误发生时立即终止。cleanUp
:任务取消时的清理回调(实验性功能)。
典型场景:
// 并行加载用户数据
Future.wait([
fetchProfile(),
fetchOrders(),
fetchMessages()
]).then((results) {
Profile profile = results[0];
List<Order> orders = results[1];
List<Message> messages = results[2];
});
错误处理策略:
// 统一错误处理
Future.wait([task1, task2], eagerError: true)
.then(handleSuccess)
.catchError(handleAllErrors);
⑥、方法对比与选型指南
方法 | 核心能力 | 适用场景 | 风险点 |
---|---|---|---|
any() | 竞速获取最快结果 | 多源择优、超时竞争 | 未完成任务泄漏 |
forEach() | 顺序异步遍历 | 有依赖的批量操作 | 性能低下 |
doWhile() | 条件异步循环 | 分页加载、轮询检查 | 无限循环 |
asStream() | Future →Stream 转换 | 适配响应式编程 | 多次监听重复执行 |
wait() | 并行执行多个任务 | 聚合多个异步任务结果 | 内存占用较高 |
四、基本用法
4.1、Future
的常见创建方式
graph LR
D[创建方法] --> D1[直接创建]
D1 --> D1a("Future(() => 耗时操作)")
D --> D2[延迟执行]
D2 --> D2a("Future.delayed(时长, 回调)")
D --> D3[快速包装]
D3 --> D3a("Future.value(结果)")
D3 --> D3b("Future.error(异常)")
①、直接创建异步任务
// 创建并立即执行异步任务
Future<String> fetchData = Future(() {
// 模拟耗时操作
return "Success";
});
- 应用场景:文件读写、网络请求、复杂计算等耗时操作。
- 执行时机:通过
Timer.run
加入事件队列,稍后执行。
②、延迟执行
// 2秒后执行任务
Future.delayed(Duration(seconds: 2), () {
print("延迟任务触发");
});
- 适用场景:
定时刷新
、动画延迟
、重试机制
等。 - 底层机制:基于
Dart
的Timer
实现。
③、快速包装值
// 同步立即返回结果
Future.value(42).then(print); // 输出 42
// 包装错误结果
Future.error(Exception("数据异常")).catchError(print);
- 典型应用:
缓存优先策略
、快速失败机制
。
4.2、结果处理核心方法
graph TB
E[处理方法] --> E1[结果处理]
E1 --> E1a(then)
E1 --> E1b(whenComplete)
E --> E2[错误处理]
E2 --> E2a(catchError)
E2 --> E2b(onError)
①、then()
:成功回调
fetchUserInfo()
.then((user) => print("用户数据: $user"))
.then((_) => print("准备加载订单"));
- 链式特性:支持返回新值或
Future
进行流水线处理。 - 执行顺序:前一个
then
完成才会触发下一个。
②、catchError()
:错误处理
Future(() => throw FormatException())
.then(processData)
.catchError((e) => print("捕获到错误: $e"));
- 错误穿透:错误会跳过后续
then
直到被捕获。 - 类型过滤:
.catchError(handleFormatError, test: (e) => e is FormatException)
③、whenComplete()
:最终清理
showLoading();
fetchData()
.then(updateUI)
.catchError(showError)
.whenComplete(hideLoading); // 类似 finally
- 必执行:
无论成功失败都会触发
。 - 典型用途:
关闭对话框
、释放资源
、日志记录
等。
4.3、async/await
:异步代码同步写法
graph TB
E3[流程控制]
E3 --> E3a(async/await)
E3 --> E3b(Future.wait)
E3 --> E3c(Future.any)
①、基础用法
void loadData() async {
try {
String data = await http.get(url);
File file = await saveToLocal(data);
print("文件保存至: ${file.path}");
} on SocketException {
print("网络连接失败");
} catch (e) {
print("未知错误: $e");
} finally {
hideProgress();
}
}
- 执行流程:遇到
await
暂停执行,但不阻塞主线程。 - 错误处理:必须用
try-catch
捕获同步/异步错误。
②、并行优化
// 同时发起三个独立请求
Future.wait([
fetchUser(),
fetchOrders(),
fetchMessages()
]).then((results) {
final user = results[0];
final orders = results[1];
final messages = results[2];
});
- 性能提升:总耗时
≈
最慢的单个请求耗时。 - 错误处理:任一失败会导致整个
wait
失败。
4.4、基础综合应用
官方计数器项目异步实现:
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
/// 标识任务的状态
enum TaskState {
initial, //初始状态
loading, //加载中状态
error, //任务异常结束状态
}
class FutureDemo extends StatefulWidget {
const FutureDemo({super.key});
@override
State<FutureDemo> createState() => _FutureDemoState();
}
class _FutureDemoState extends State<FutureDemo> {
int _counter = 0;
TaskState _state = TaskState.initial;
void _doIncrementTask() async {
renderLoading();
// 1、模拟异步任务
await Future.delayed(const Duration(seconds: 2));
// 2、模拟同步等待任务耗时
// sleep(const Duration(seconds: 2));
_counter++;
renderLoaded();
// 3、模拟异步任务 异常场景
// try {
// _counter = await Future.delayed(const Duration(seconds: 2), computation);
// renderLoaded();
// } catch (e) {
// renderError();
// }
}
FutureOr<int> computation() {
int counter = _counter + 1;
if (counter % 3 == 0) {
_counter = 0;
throw 'error';
}
return counter;
}
void renderError() {
setState(() {
_state = TaskState.error;
});
}
void renderLoading() {
setState(() {
_state = TaskState.loading;
});
}
void renderLoaded() {
setState(() {
_state = TaskState.initial;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blueAccent,
title: Text("Future Demo"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'按压次数:',
),
Text(
'$_counter',
style: TextStyle(fontSize: 24, color: Colors.blue),
),
],
),
),
floatingActionButton: buildButtonByState(_state),
);
}
Widget buildButtonByState(TaskState state) {
VoidCallback? onPressed;
Color color;
Widget child;
switch (state) {
case TaskState.initial:
child = const Icon(Icons.add, color: Colors.white);
onPressed = _doIncrementTask;
color = Colors.blueAccent;
break;
case TaskState.loading:
child = const CupertinoActivityIndicator(color: Colors.white);
color = Colors.blueGrey;
onPressed = null;
break;
case TaskState.error:
child = const Icon(Icons.refresh);
color = Colors.red;
onPressed = renderLoaded;
break;
}
return FloatingActionButton(
onPressed: onPressed,
backgroundColor: color,
shape: CircleBorder(),
child: child,
);
}
}
五、最佳实践与避坑指南
✅ 最佳实践:
优先使用async/await
:
// 错误示例:回调嵌套
future1.then((v1) {
future2(v1).then((v2) {
future3(v2).then((v3) {...});
});
});
// 正确写法:线性结构
var v1 = await future1;
var v2 = await future2(v1);
var v3 = await future3(v2);
超时处理:
var response = await fetchData().timeout(
Duration(seconds: 10),
onTimeout: () => throw NetworkException()
);
避免不必要的async
:
// 错误:增加不必要的异步开销
Future<int> add(int a, int b) async {
return a + b;
}
// 正确:同步方法
int add(int a, int b) => a + b;
⚠️ 常见坑点:
- 未捕获的异常:忘记
catchError
导致APP
崩溃。- 误用
whenComplete
:内部不能修改返回值。
六、关联技术对比
对比维度 | Future | Stream | Isolate |
---|---|---|---|
数据次数 | 单次值 | 多次值 | 并行计算 |
内存隔离 | 共享内存 | 共享内存 | 独立内存 |
典型场景 | 网络请求结果 | 聊天消息推送 | 图像压缩 |
语法复杂度 | ★☆☆☆☆ | ★★☆☆☆ | ★★★★☆ |
选型建议:
- 简单异步任务 →
Future
。- 持续事件流 →
Stream
。CPU
密集型任务 →Isolate
。
七、进阶应用:企业级实战案例
7.1、智能分页加载
场景需求:实现列表分页加载,支持自动重试
、并发控制
、页面保序
。
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:math';
/// 分页演示页面
class PaginationDemo extends StatefulWidget {
const PaginationDemo({super.key});
@override
State<PaginationDemo> createState() => _PaginationDemoState();
}
class _PaginationDemoState extends State<PaginationDemo> {
final ScrollController _scrollController = ScrollController();
final List<Item> _items = [];
int _currentPage = 1;
bool _isLoading = false;
bool _hasError = false;
bool _hasMore = true;
@override
void initState() {
super.initState();
_loadFirstPage();
_scrollController.addListener(_scrollListener);
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
// 滚动监听
void _scrollListener() {
if (_scrollController.position.pixels >
_scrollController.position.maxScrollExtent - 200) {
_loadMore();
}
}
// 加载第一页
Future<void> _loadFirstPage() async {
setState(() => _isLoading = true);
try {
final data = await _fetchData(page: 1);
setState(() {
_items.addAll(data);
_currentPage = 2;
_hasMore = data.isNotEmpty;
});
} catch (e) {
setState(() => _hasError = true);
} finally {
setState(() => _isLoading = false);
}
}
// 加载更多
Future<void> _loadMore() async {
if (!_hasMore || _isLoading || _hasError) return;
setState(() {
_isLoading = true;
_hasError = false;
});
try {
final data = await _fetchData(page: _currentPage);
setState(() {
if (data.isEmpty) {
_hasMore = false;
} else {
_items.addAll(data);
_currentPage++;
}
});
} catch (e) {
setState(() => _hasError = true);
} finally {
setState(() => _isLoading = false);
}
}
// 模拟数据获取
Future<List<Item>> _fetchData({required int page}) async {
// 模拟网络延迟
await Future.delayed(const Duration(seconds: 1));
// 模拟错误(随机失败)
if (Random().nextDouble() < 0.2 && page > 1) {
throw Exception('网络请求失败');
}
// 生成测试数据
return List.generate(
15,
(index) => Item(
id: (page - 1) * 15 + index,
title: '项目 ${(page - 1) * 15 + index + 1}',
color:
Colors.primaries[Random().nextInt(Colors.primaries.length)],
));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('智能分页加载示例'),
),
body: RefreshIndicator(
onRefresh: _loadFirstPage,
child: ListView.builder(
controller: _scrollController,
itemCount: _items.length + 1,
itemBuilder: (context, index) {
if (index < _items.length) {
return _ListItem(item: _items[index]);
}
return _buildFooter();
},
),
),
);
}
// 底部状态显示
Widget _buildFooter() {
if (_hasError) {
return _ErrorRetry(
onRetry: _loadMore,
);
}
if (_isLoading) {
return const _LoadingIndicator();
}
if (!_hasMore) {
return const _NoMoreItems();
}
return Container();
}
}
/// 列表项组件
class _ListItem extends StatelessWidget {
final Item item;
const _ListItem({required this.item});
@override
Widget build(BuildContext context) {
return Container(
height: 80,
margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
decoration: BoxDecoration(
color: item.color.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(8),
),
child: ListTile(
title: Text(item.title),
subtitle: Text('ID: ${item.id}'),
trailing: const Icon(Icons.chevron_right),
),
);
}
}
// 加载指示器
class _LoadingIndicator extends StatelessWidget {
const _LoadingIndicator();
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: CircularProgressIndicator(),
),
);
}
}
// 错误重试组件
class _ErrorRetry extends StatelessWidget {
final VoidCallback onRetry;
const _ErrorRetry({required this.onRetry});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const Text('加载失败,请重试', style: TextStyle(color: Colors.red)),
const SizedBox(height: 8),
ElevatedButton(
onPressed: onRetry,
child: const Text('重试'),
),
],
),
);
}
}
// 没有更多数据
class _NoMoreItems extends StatelessWidget {
const _NoMoreItems();
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.all(16.0),
child: Center(
child: Text('已经到底了~', style: TextStyle(color: Colors.grey)),
),
);
}
}
// 数据模型
class Item {
final int id;
final String title;
final Color color;
Item({
required this.id,
required this.title,
required this.color,
});
}
核心技术:
ScrollController
监听滚动位置。RefreshIndicator
实现下拉刷新。- 状态管理:
_isLoading
,_hasError
,_hasMore
。 - 分页数据合并:
_items.addAll(data)
。 - 随机失败模拟:测试错误处理。
UI 组件化:
_ListItem
:统一列表项样式。_LoadingIndicator
:加载动画。_ErrorRetry
:错误提示与重试按钮。_NoMoreItems
:数据结束提示。
注意事项:
- 网络层需实现重试策略。
- 服务端返回数据需包含分页元数据(
总页数/是否最后一页
)。
7.2、多服务聚合查询
场景需求:同时请求多个微服务,合并处理数据
。
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:math';
/// 聚合查询演示页面
class ServiceAggregationDemo extends StatefulWidget {
const ServiceAggregationDemo({super.key});
@override
State<ServiceAggregationDemo> createState() => _ServiceAggregationDemoState();
}
class _ServiceAggregationDemoState extends State<ServiceAggregationDemo> {
late ProfileAggregateData _aggregateData;
Map<ServiceType, LoadState> _loadStates = {
ServiceType.userInfo: LoadState.initial,
ServiceType.orders: LoadState.initial,
ServiceType.messages: LoadState.initial,
};
Object? _globalError;
@override
void initState() {
super.initState();
_aggregateData = ProfileAggregateData();
_loadAllData();
}
// 加载所有数据
Future<void> _loadAllData() async {
setState(() {
_globalError = null;
_loadStates = _loadStates.map((key, value) => MapEntry(key, LoadState.loading));
});
try {
final results = await Future.wait([
_fetchUserInfo(),
_fetchOrders(),
_fetchMessages(),
], eagerError: true);
setState(() {
_aggregateData = ProfileAggregateData(
userInfo: results[0] as UserInfo,
orders: results[1] as List<Order>,
messages: results[2] as List<Message>,
);
_loadStates = _loadStates.map((key, value) => MapEntry(key, LoadState.success));
});
} catch (e) {
setState(() {
_globalError = e;
_handlePartialErrors(e);
});
}
}
// 处理部分错误(企业级实现示例)
void _handlePartialErrors(Object error) {
final updatedStates = Map<ServiceType, LoadState>.from(_loadStates);
if (error is UserInfoException) {
updatedStates[ServiceType.userInfo] = LoadState.error;
_aggregateData.userInfo = UserInfo.fallback();
}
if (error is OrdersException) {
updatedStates[ServiceType.orders] = LoadState.error;
_aggregateData.orders = [];
}
if (error is MessagesException) {
updatedStates[ServiceType.messages] = LoadState.error;
_aggregateData.messages = [];
}
setState(() {
_loadStates = updatedStates;
});
}
// 模拟用户信息服务
Future<UserInfo> _fetchUserInfo() async {
await Future.delayed(Duration(seconds: 1 + Random().nextInt(2)));
if (Random().nextDouble() < 0.3) throw UserInfoException();
return UserInfo(
name: "张三",
email: "zhangsan@example.com",
avatar: Color(0xFF000000 + Random().nextInt(0xFFFFFF)),
);
}
// 模拟订单服务
Future<List<Order>> _fetchOrders() async {
await Future.delayed(Duration(seconds: 2 + Random().nextInt(2)));
if (Random().nextDouble() < 0.3) throw OrdersException();
return List.generate(3, (i) => Order(
id: "ORDER_${DateTime.now().millisecondsSinceEpoch}",
amount: 100 * (i + 1),
date: DateTime.now().subtract(Duration(days: i)),
));
}
// 模拟消息服务
Future<List<Message>> _fetchMessages() async {
await Future.delayed(Duration(seconds: 3 + Random().nextInt(2)));
if (Random().nextDouble() < 0.3) throw MessagesException();
return List.generate(5, (i) => Message(
id: i,
content: "重要通知 ${i + 1}",
isRead: i > 2,
));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('服务聚合查询'),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: _loadAllData,
),
],
),
body: _buildContent(),
);
}
Widget _buildContent() {
if (_globalError != null && _isAllFailed()) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('全部服务请求失败', style: TextStyle(color: Colors.red)),
ElevatedButton(
onPressed: _loadAllData,
child: const Text('重新加载'),
),
],
),
);
}
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildUserSection(),
_buildOrdersSection(),
_buildMessagesSection(),
if (_hasAnyError()) _buildErrorBanner(),
],
),
),
);
}
Widget _buildUserSection() {
return _buildServiceCard(
title: '用户信息',
state: _loadStates[ServiceType.userInfo]!,
content: Column(
children: [
CircleAvatar(
backgroundColor: _aggregateData.userInfo.avatar,
child: Text(_aggregateData.userInfo.name[0]),
),
const SizedBox(height: 8),
Text(_aggregateData.userInfo.name, style: Theme.of(context).textTheme.titleLarge),
Text(_aggregateData.userInfo.email),
],
),
onRetry: () => _retryService(ServiceType.userInfo),
);
}
Widget _buildOrdersSection() {
return _buildServiceCard(
title: '最近订单 (${_aggregateData.orders.length}笔)',
state: _loadStates[ServiceType.orders]!,
content: Column(
children: [
if (_aggregateData.orders.isEmpty)
const Text('暂无订单', style: TextStyle(color: Colors.grey)),
..._aggregateData.orders.map((order) => ListTile(
title: Text('订单号: ${order.id}'),
subtitle: Text('金额: ¥${order.amount}'),
trailing: Text('${order.date.year}-${order.date.month}'),
)),
],
),
onRetry: () => _retryService(ServiceType.orders),
);
}
Widget _buildMessagesSection() {
return _buildServiceCard(
title: '未读消息 (${_aggregateData.messages.where((m) => !m.isRead).length}条)',
state: _loadStates[ServiceType.messages]!,
content: Column(
children: [
if (_aggregateData.messages.isEmpty)
const Text('没有新消息', style: TextStyle(color: Colors.grey)),
..._aggregateData.messages.map((msg) => ListTile(
title: Text(msg.content),
leading: Icon(msg.isRead ? Icons.mark_email_read : Icons.markunread),
)),
],
),
onRetry: () => _retryService(ServiceType.messages),
);
}
Widget _buildServiceCard({
required String title,
required LoadState state,
required Widget content,
required VoidCallback onRetry,
}) {
return Card(
margin: const EdgeInsets.only(bottom: 16),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
Text(title, style: Theme.of(context).textTheme.titleMedium),
const Spacer(),
_buildStateIndicator(state),
],
),
const Divider(),
if (state == LoadState.loading)
const Center(child: CircularProgressIndicator()),
if (state == LoadState.error)
Column(
children: [
const Icon(Icons.error, color: Colors.red),
ElevatedButton(
onPressed: onRetry,
child: const Text('重试'),
),
],
),
if (state == LoadState.success) content,
],
),
),
);
}
Widget _buildStateIndicator(LoadState state) {
switch (state) {
case LoadState.loading:
return const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(strokeWidth: 2),
);
case LoadState.error:
return const Icon(Icons.error, color: Colors.red, size: 24);
case LoadState.success:
return const Icon(Icons.check_circle, color: Colors.green, size: 24);
default:
return const SizedBox.shrink();
}
}
Widget _buildErrorBanner() {
return Container(
padding: const EdgeInsets.all(8),
color: Colors.orange[100],
child: Row(
children: [
const Icon(Icons.warning, color: Colors.orange),
const SizedBox(width: 8),
const Expanded(child: Text('部分服务加载失败,已显示降级数据')),
TextButton(
onPressed: _loadAllData,
child: const Text('全部重试'),
),
],
),
);
}
Future<void> _retryService(ServiceType type) async {
setState(() => _loadStates[type] = LoadState.loading);
try {
switch (type) {
case ServiceType.userInfo:
_aggregateData.userInfo = await _fetchUserInfo();
break;
case ServiceType.orders:
_aggregateData.orders = await _fetchOrders();
break;
case ServiceType.messages:
_aggregateData.messages = await _fetchMessages();
break;
}
setState(() => _loadStates[type] = LoadState.success);
} catch (e) {
setState(() => _loadStates[type] = LoadState.error);
}
}
bool _isAllFailed() => _loadStates.values.every((s) => s == LoadState.error);
bool _hasAnyError() => _loadStates.values.any((s) => s == LoadState.error);
}
// 状态枚举
enum LoadState { initial, loading, success, error }
enum ServiceType { userInfo, orders, messages }
// 数据模型
class ProfileAggregateData {
UserInfo userInfo;
List<Order> orders;
List<Message> messages;
ProfileAggregateData({
this.userInfo = const UserInfo.fallback(),
this.orders = const [],
this.messages = const [],
});
}
class UserInfo {
final String name;
final String email;
final Color avatar;
const UserInfo({
required this.name,
required this.email,
required this.avatar,
});
const UserInfo.fallback()
: name = "未知用户",
email = "未获取到邮箱",
avatar = Colors.grey;
}
class Order {
final String id;
final double amount;
final DateTime date;
Order({
required this.id,
required this.amount,
required this.date,
});
}
class Message {
final int id;
final String content;
final bool isRead;
Message({
required this.id,
required this.content,
required this.isRead,
});
}
// 自定义异常
class UserInfoException implements Exception {}
class OrdersException implements Exception {}
class MessagesException implements Exception {}
核心技术:
- 状态机管理:使用
枚举类型
管理每个服务的状态。 - 错误隔离:单个服务失败
不影响
其他服务显示。 - 优雅降级:关键数据提供默认值(如
用户信息
)。 - 性能优化:
Future.wait
实现并行请求。 - 企业级异常分类:
自定义业务异常类型
。
该实现展示了企业级应用的关键特性:稳定性(错误隔离
)、可用性(降级处理
)、可观察性(状态提示
)。还可以在此基础上扩展服务监控
、性能分析
等高级功能。
八、总结
Future
不仅是Flutter
中的技术组件,更是一种异步编程范式的具象体现。就像在生活中学会"多线程处理"
能提升效率,掌握Future``的核心原理
、方法链
、错误处理
,将使你的APP
具备"行云流水"
般的用户体验。
记住三个关键点:状态不可逆
、异常必捕获
、异步不阻塞
。建议将本文案例融入实际项目,通过"实现-调试-优化"
的闭环,逐步构建起系统化的异步处理思维,这将是成长为高级Flutter
开发者的重要里程碑!
欢迎一键四连(
关注
+点赞
+收藏
+评论
)