系统化掌握Dart编程之异步编程(三):打通Future任督二脉

570 阅读15分钟

image.png

前言

想象这样一个场景:你在外卖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():将一次性结果转为流式监听(适合多次监听场景)。

四、核心方法深入剖析

企业微信截图_17427242759402.png

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()FutureStream 转换适配响应式编程多次监听重复执行
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("延迟任务触发");
});
  • 适用场景定时刷新动画延迟重试机制等。
  • 底层机制:基于 DartTimer 实现。

③、快速包装值

// 同步立即返回结果
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:内部不能修改返回值。

六、关联技术对比

对比维度FutureStreamIsolate
数据次数单次值多次值并行计算
内存隔离共享内存共享内存独立内存
典型场景网络请求结果聊天消息推送图像压缩
语法复杂度★☆☆☆☆★★☆☆☆★★★★☆

选型建议

  • 简单异步任务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开发者的重要里程碑

欢迎一键四连关注 + 点赞 + 收藏 + 评论